which included commits to RCS files with non-trunk default branches.
--- /dev/null
+/*by Pabs (pabs3@zip.to, http://zip.to/pabs3) Nov 2001, April 2002*/\r
+\r
+/*Licenced under the BSD sloppyright - nasty little daemons better not use this source & not attribute me*/\r
+/*Why BSD licence? HTFSIK but seriously I wanted to get to know more open/free licences*/\r
+\r
+/*Compile notes:\r
+ M$VC: just open this file & press the build button or select build from the\r
+ build menu since this will create a default project that does nicely\r
+ GCC/Cygwin: gcc -mno-cygwin -fvtable-thunks -lole32 -o istorage.exe istorage.cpp should do the trick\r
+ if w32api & mingw are set up correctly & the headers are correct\r
+ GCC/Wine: You'll have to figure it out for yourself since I don't yet have\r
+ access to Linux (Debian) cause I need a new HD + a DVD drive ;-)\r
+*/\r
+\r
+/*Usage:\r
+ istorage some.doc some.xls some.pub some.fla some.chm\r
+ will extract each of these files to some.???.Contents directories\r
+ these are M$ Word, Excel and Publisher and Macromedia Flash source files (ooh and a compiled HTML Help file)\r
+*/\r
+\r
+/*TODO:\r
+ think up a proper name - unist??? or what??\r
+ Add popt/getopt processing\r
+ reverse engineer the compound file format (& chm format - Matthew T. Russotto has already done some)\r
+ or just use libOLE - http://chicago.sf.net\r
+ so we don't depend on M$ for the implementation\r
+ Implement options for the following\r
+ -i string invalid chars\r
+ -f char replace invalid chars with\r
+ -n char indent with this char\r
+ -a string append this to each file opened\r
+ various tar/unzip options\r
+ --help --version\r
+*/\r
+\r
+\r
+#include <windows.h>\r
+#include <ole2.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+\r
+\r
+struct OPTIONS{\r
+ char fixchar;\r
+ char* invalidchars;\r
+ char indentchar;\r
+ char* appendstring;\r
+} options = {'.',"<>|/\\\"",'\t',".Contents"};\r
+\r
+HRESULT r;\r
+\r
+DWORD level = 0;\r
+\r
+//These next few bits are from a sample available from http://www.keyworks.net/code.htm (see http://helpware.net/delphi/index.html for a Delphi sample - need to join a yahoo group first - example 10 is the one to look at)\r
+//This stuff is supposed to be documented in the MSDN, but I only found 1 page that references ITStorage & that is an error codes list\r
+DEFINE_GUID(CLSID_ITStorage, 0x5d02926a, 0x212e, 0x11d0, 0x9d, 0xf9, 0x0, 0xa0, 0xc9, 0x22, 0xe6, 0xec);\r
+DEFINE_GUID(IID_ITStorage, 0x88cc31de, 0x27ab, 0x11d0, 0x9d, 0xf9, 0x0, 0xa0, 0xc9, 0x22, 0xe6, 0xec);\r
+\r
+const GUID CLSID_ITStorage = { 0x5d02926a, 0x212e, 0x11d0, { 0x9d, 0xf9, 0x0, 0xa0, 0xc9, 0x22, 0xe6, 0xec } };\r
+const GUID IID_ITStorage = { 0x88cc31de, 0x27ab, 0x11d0, { 0x9d, 0xf9, 0x0, 0xa0, 0xc9, 0x22, 0xe6, 0xec} };\r
+\r
+typedef struct _ITS_Control_Data\r
+{\r
+ UINT cdwControlData; // Number of DWords to follow.\r
+ UINT adwControlData[1]; // Actually this will be adwControlData[cdwControlData]\r
+} ITS_Control_Data, *PITS_Control_Data;\r
+\r
+typedef enum ECompactionLev {\r
+ COMPACT_DATA = 0,\r
+ COMPACT_DATA_AND_PATH\r
+};\r
+\r
+DECLARE_INTERFACE_(IITStorage, IUnknown)\r
+{\r
+ STDMETHOD(StgCreateDocfile) (const WCHAR* pwcsName, DWORD grfMode, DWORD reserved, IStorage** ppstgOpen) PURE;\r
+ STDMETHOD(StgCreateDocfileOnILockBytes) (ILockBytes * plkbyt, DWORD grfMode, DWORD reserved, IStorage** ppstgOpen) PURE;\r
+ STDMETHOD(StgIsStorageFile) (const WCHAR * pwcsName) PURE;\r
+ STDMETHOD(StgIsStorageILockBytes) (ILockBytes * plkbyt) PURE;\r
+ STDMETHOD(StgOpenStorage)(const WCHAR * pwcsName, IStorage * pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage ** ppstgOpen) PURE;\r
+ STDMETHOD(StgOpenStorageOnILockBytes)(ILockBytes * plkbyt, IStorage * pStgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage ** ppstgOpen) PURE;\r
+ STDMETHOD(StgSetTimes)(WCHAR const* lpszName, FILETIME const* pctime, FILETIME const* patime, FILETIME const* pmtime) PURE;\r
+ STDMETHOD(SetControlData)(PITS_Control_Data pControlData) PURE;\r
+ STDMETHOD(DefaultControlData)(PITS_Control_Data *ppControlData) PURE;\r
+ STDMETHOD(Compact)(const WCHAR* pwcsName, ECompactionLev iLev) PURE;\r
+};\r
+\r
+IITStorage* ITStorage = NULL;\r
+\r
+void EnumStorage(IStorage* is);\r
+void fixpath(char* s);\r
+\r
+int main(int argc, char *argv[]){\r
+ //Get an instance of the thing to call for opening chms\r
+ CoInitialize(NULL);\r
+ CoCreateInstance(CLSID_ITStorage, NULL, CLSCTX_INPROC_SERVER, IID_ITStorage, (void**)&ITStorage);\r
+ for(int i=1;i<argc;i++){\r
+ for(DWORD ii=0;ii<level;ii++)fputc(options.indentchar,stderr);\r
+ fputs(argv[i],stderr);\r
+ fputs(": ",stderr);\r
+ DWORD len = strlen(argv[i]);\r
+ DWORD wlen = MultiByteToWideChar(CP_ACP,0,argv[i],len+1,NULL,0);\r
+ WCHAR* wpath = new WCHAR[len+1];\r
+ if(wpath){\r
+ if(MultiByteToWideChar(CP_ACP,0,argv[i],len+1,wpath,wlen)){\r
+ IStorage* is = NULL;\r
+ r = StgOpenStorage(wpath,NULL,STGM_READ|STGM_SHARE_EXCLUSIVE,NULL,0,&is);\r
+ if( ITStorage && r != S_OK && is == NULL ){\r
+ r = ITStorage->StgOpenStorage(wpath,NULL,STGM_READ|STGM_SHARE_DENY_WRITE,NULL,0,&is);\r
+ fputs("StgOpenStorage failed, trying chm version...",stderr);\r
+ }\r
+ delete[]wpath; wpath = NULL;\r
+ if( r == S_OK || is ){\r
+ STATSTG ss;\r
+ if(S_OK==is->Stat(&ss,STATFLAG_NONAME))fprintf(stderr,"CLSID={%8.8X-%4.4X-%4.4X-%4.4X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X} State=0x%8.8X reserved=0x%8.8X\n", ss.clsid.Data1, ss.clsid.Data2, ss.clsid.Data3, ss.clsid.Data4[0]<<8/*&0xff00*/| ss.clsid.Data4[1], ss.clsid.Data4[2], ss.clsid.Data4[3], ss.clsid.Data4[4], ss.clsid.Data4[5], ss.clsid.Data4[6], ss.clsid.Data4[7], ss.grfStateBits, ss.reserved);\r
+ else fputs("Stat failed\n",stderr);\r
+ char* path = new char[len+strlen(options.appendstring)+1];\r
+ if(path){\r
+ strcpy(path,argv[i]);\r
+ strcpy(&path[len],options.appendstring);\r
+ RemoveDirectory(path);\r
+ if(CreateDirectory(path,NULL)||GetLastError()==ERROR_ALREADY_EXISTS){\r
+ if(SetCurrentDirectory(path)){\r
+ delete[]path; path = NULL;\r
+ level++;\r
+ EnumStorage(is);\r
+ level--;\r
+ SetCurrentDirectory("..");\r
+ }\r
+ else fputs("Could not enter - Ignoring & continuing\n",stderr);\r
+ }\r
+ else fputs("Could not create (directory) - Ignoring & continuing\n",stderr);\r
+ delete[]path; path = NULL;\r
+ }\r
+ else fputs("Could not alloc memory for the ANSI pathname for the wimpy Win9$ - Ignoring & continuing\n",stderr);\r
+ is->Release();\r
+ }\r
+ else fputs("Could not open the specified file - Ignoring & continuing\n",stderr);\r
+ }\r
+ else fputs("Could not convert the path to Unicode for the Unicode only StgOpenStorage - Ignoring & continuing\n",stderr);\r
+ delete[]wpath; wpath = NULL;\r
+ }\r
+ else fputs("Could not alloc memory for the Unicode filename for the Unicode only StgOpenStorage - Ignoring & continuing",stderr);\r
+ }\r
+ if( ITStorage ) ITStorage->Release();\r
+ CoUninitialize();\r
+ fflush(stderr);//Helps with debugging\r
+ return 0;\r
+}\r
+\r
+void EnumStorage(IStorage* is){\r
+ IEnumSTATSTG* iess;\r
+ r = is->EnumElements(0,NULL,0,&iess);\r
+ if( r!= S_OK ) { fputs("Could not enumerate elements - Ignoring & continuing\n",stderr); return;}\r
+ STATSTG ss;\r
+ iess->Reset();\r
+ for(;;){\r
+ r=iess->Next(1,&ss,NULL);\r
+ if( r!= S_OK ) break;\r
+ for(DWORD i=0;i<level;i++)fputc(options.indentchar,stderr);\r
+ fputws(ss.pwcsName,stderr);\r
+ fputs(": ",stderr);\r
+ fprintf(stderr,"CLSID={%8.8X-%4.4X-%4.4X-%4.4X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X} State=0x%8.8X reserved=0x%8.8X\n", ss.clsid.Data1, ss.clsid.Data2, ss.clsid.Data3, ss.clsid.Data4[0]<<8/*&0xff00*/| ss.clsid.Data4[1], ss.clsid.Data4[2], ss.clsid.Data4[3], ss.clsid.Data4[4], ss.clsid.Data4[5], ss.clsid.Data4[6], ss.clsid.Data4[7], ss.grfStateBits, ss.reserved);\r
+ DWORD len = wcslen(ss.pwcsName);\r
+ char* path = new char[len+1];\r
+ if(path){\r
+ if(WideCharToMultiByte(CP_ACP,0,ss.pwcsName,len+1,path,len+1,NULL,NULL)){\r
+ fixpath(path);\r
+ switch(ss.type){\r
+ case STGTY_STORAGE:{\r
+ IStorage* is2;\r
+ r = is->OpenStorage(ss.pwcsName,NULL,STGM_READ|STGM_SHARE_EXCLUSIVE,NULL,0,&is2);\r
+ CoTaskMemFree(ss.pwcsName); ss.pwcsName = NULL;\r
+ if( r == S_OK || is2 ){\r
+ if(CreateDirectory(path,NULL)||(r=GetLastError())==ERROR_ALREADY_EXISTS){\r
+ if(r==ERROR_ALREADY_EXISTS)fputs("Already exists (directory) - using anyway\n",stderr);\r
+ else fputs("Created (directory)\n",stderr);\r
+ HANDLE f = CreateFile(path,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);\r
+ if(f!=INVALID_HANDLE_VALUE&&f!=0/*Fucking lying MSDN*/){\r
+ if(!SetFileTime(f,&ss.ctime,&ss.atime,&ss.mtime))fputs("Could not set the creation, last modification or last access time\n",stderr);\r
+ CloseHandle(f);\r
+ }\r
+ if(SetCurrentDirectory(path)){\r
+ delete[]path; path = NULL;\r
+ level++;\r
+ EnumStorage(is2);\r
+ level--;\r
+ SetCurrentDirectory("..");\r
+ }\r
+ else fputs("Could not enter (directory) - Ignoring & continuing\n",stderr);\r
+ }\r
+ else fputs("Could not create (directory) - Ignoring & continuing\n",stderr);\r
+ is2->Release();\r
+ }\r
+ else fputs("Could not open (directory) - Ignoring & continuing\n",stderr);\r
+ }break;\r
+ case STGTY_STREAM:{\r
+ IStream* is2;\r
+ r = is->OpenStream(ss.pwcsName,NULL,STGM_READ|STGM_SHARE_EXCLUSIVE,0,&is2);\r
+ CoTaskMemFree(ss.pwcsName); ss.pwcsName = NULL;\r
+ if( r == S_OK ){\r
+ HANDLE f = CreateFile(path,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);\r
+ delete[]path; path = NULL;\r
+ if(f!=INVALID_HANDLE_VALUE&&f!=0/*Fucking lying MSDN*/){\r
+ if(ERROR_ALREADY_EXISTS==GetLastError())fputs("Already exists (file) - overwriting\n",stderr);\r
+ else fputs("Created (file)\n",stderr);\r
+ //This bit, although a bit more complex than 1 byte at a time, is way faster\r
+ BYTE* p;\r
+ ULARGE_INTEGER i={0};\r
+ DWORD nobm = (DWORD)ss.cbSize.QuadPart, nobr, nobw;\r
+ bool err;\r
+ for(;;){\r
+ p = (BYTE*)malloc( nobm ); if(p)break;\r
+ nobm/=2; if(!nobm)break;\r
+ }\r
+ if(p){\r
+ do{\r
+ r=is2->Read(p,nobm,&nobr);\r
+ if(r!=S_OK&&nobm!=nobr){fputs("Read error (file) - terminating this file\n",stderr);err=true;}//read less than asked and there was an error other than EOF - MSDN says that the compound file implementation of Read returns S_OK if the end of the stream was reached during the read\r
+ nobw=0;\r
+ r=WriteFile(f,p,nobr,&nobw,NULL);\r
+ i.QuadPart+=nobw;\r
+ if(!r||nobr!=nobw){fputs("Write error (file) - terminating this file\n",stderr);err=true;}\r
+ } while (i.QuadPart<ss.cbSize.QuadPart&&!err);\r
+ free(p); p = NULL;\r
+ }\r
+ //Note that for(uint i=randint();!i;i/=2); will always go through i=1 to i=0\r
+ else{ fputs("Could not alloc even 1 byte of mem for a buffer for transferring files - please free some memory & try again - Ignoring & continuing\n",stderr); err=true;}\r
+ if(!SetFileTime(f,&ss.ctime,&ss.atime,&ss.mtime))fputs("Could not set the creation, last modification or last access time - Ignoring & continuing\n",stderr);\r
+ CloseHandle(f);\r
+ }\r
+ else fputs("Could not create (file) - Ignoring & continuing\n",stderr);\r
+ is2->Release();\r
+ }\r
+ else fputs("Could not open (file) - Ignoring & continuing\n",stderr);\r
+ }break;\r
+ case STGTY_LOCKBYTES:\r
+ fputs("unsupported ILockBytes object - Ignoring & continuing\n",stderr);\r
+ break;\r
+ case STGTY_PROPERTY:\r
+ fputs("unsupported property storage object - Ignoring & continuing\n",stderr);\r
+ break;\r
+ default:\r
+ fputs("unknown object - Ignoring & continuing\n",stderr);\r
+ break;\r
+ }\r
+ }\r
+ else fputs("Could not convert the path back to ANSI for the wimpy Win9$ - Ignoring & continuing\n",stderr);\r
+ delete[]path; path = NULL;\r
+ }\r
+ else fputs("Could not alloc memory for the ANSI pathname for the wimpy Win9$ - Ignoring & continuing\n",stderr);\r
+ CoTaskMemFree(ss.pwcsName); ss.pwcsName = NULL;\r
+ }\r
+ iess->Release();\r
+}\r
+\r
+void fixpath(char* s){\r
+ while(*s){//*s<32 || should probably be removed on non-FAT file systems\r
+ if( *s<32 || strchr(options.invalidchars,*s) )*s=options.fixchar;\r
+ s++;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE\r
+ Version 2, June 1991\r
+\r
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.\r
+ 59 Temple Place - Suite 330, Boston, MA 02111 USA\r
+ Everyone is permitted to copy and distribute verbatim copies\r
+ of this license document, but changing it is not allowed.\r
+\r
+ Preamble\r
+\r
+ The licenses for most software are designed to take away your\r
+freedom to share and change it. By contrast, the GNU General Public\r
+License is intended to guarantee your freedom to share and change free\r
+software--to make sure the software is free for all its users. This\r
+General Public License applies to most of the Free Software\r
+Foundation's software and to any other program whose authors commit to\r
+using it. (Some other Free Software Foundation software is covered by\r
+the GNU Library General Public License instead.) You can apply it to\r
+your programs, too.\r
+\r
+ When we speak of free software, we are referring to freedom, not\r
+price. Our General Public Licenses are designed to make sure that you\r
+have the freedom to distribute copies of free software (and charge for\r
+this service if you wish), that you receive source code or can get it\r
+if you want it, that you can change the software or use pieces of it\r
+in new free programs; and that you know you can do these things.\r
+\r
+ To protect your rights, we need to make restrictions that forbid\r
+anyone to deny you these rights or to ask you to surrender the rights.\r
+These restrictions translate to certain responsibilities for you if you\r
+distribute copies of the software, or if you modify it.\r
+\r
+ For example, if you distribute copies of such a program, whether\r
+gratis or for a fee, you must give the recipients all the rights that\r
+you have. You must make sure that they, too, receive or can get the\r
+source code. And you must show them these terms so they know their\r
+rights.\r
+\r
+ We protect your rights with two steps: (1) copyright the software, and\r
+(2) offer you this license which gives you legal permission to copy,\r
+distribute and/or modify the software.\r
+\r
+ Also, for each author's protection and ours, we want to make certain\r
+that everyone understands that there is no warranty for this free\r
+software. If the software is modified by someone else and passed on, we\r
+want its recipients to know that what they have is not the original, so\r
+that any problems introduced by others will not reflect on the original\r
+authors' reputations.\r
+\r
+ Finally, any free program is threatened constantly by software\r
+patents. We wish to avoid the danger that redistributors of a free\r
+program will individually obtain patent licenses, in effect making the\r
+program proprietary. To prevent this, we have made it clear that any\r
+patent must be licensed for everyone's free use or not licensed at all.\r
+\r
+ The precise terms and conditions for copying, distribution and\r
+modification follow.\r
+\f\r
+ GNU GENERAL PUBLIC LICENSE\r
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\r
+\r
+ 0. This License applies to any program or other work which contains\r
+a notice placed by the copyright holder saying it may be distributed\r
+under the terms of this General Public License. The "Program", below,\r
+refers to any such program or work, and a "work based on the Program"\r
+means either the Program or any derivative work under copyright law:\r
+that is to say, a work containing the Program or a portion of it,\r
+either verbatim or with modifications and/or translated into another\r
+language. (Hereinafter, translation is included without limitation in\r
+the term "modification".) Each licensee is addressed as "you".\r
+\r
+Activities other than copying, distribution and modification are not\r
+covered by this License; they are outside its scope. The act of\r
+running the Program is not restricted, and the output from the Program\r
+is covered only if its contents constitute a work based on the\r
+Program (independent of having been made by running the Program).\r
+Whether that is true depends on what the Program does.\r
+\r
+ 1. You may copy and distribute verbatim copies of the Program's\r
+source code as you receive it, in any medium, provided that you\r
+conspicuously and appropriately publish on each copy an appropriate\r
+copyright notice and disclaimer of warranty; keep intact all the\r
+notices that refer to this License and to the absence of any warranty;\r
+and give any other recipients of the Program a copy of this License\r
+along with the Program.\r
+\r
+You may charge a fee for the physical act of transferring a copy, and\r
+you may at your option offer warranty protection in exchange for a fee.\r
+\r
+ 2. You may modify your copy or copies of the Program or any portion\r
+of it, thus forming a work based on the Program, and copy and\r
+distribute such modifications or work under the terms of Section 1\r
+above, provided that you also meet all of these conditions:\r
+\r
+ a) You must cause the modified files to carry prominent notices\r
+ stating that you changed the files and the date of any change.\r
+\r
+ b) You must cause any work that you distribute or publish, that in\r
+ whole or in part contains or is derived from the Program or any\r
+ part thereof, to be licensed as a whole at no charge to all third\r
+ parties under the terms of this License.\r
+\r
+ c) If the modified program normally reads commands interactively\r
+ when run, you must cause it, when started running for such\r
+ interactive use in the most ordinary way, to print or display an\r
+ announcement including an appropriate copyright notice and a\r
+ notice that there is no warranty (or else, saying that you provide\r
+ a warranty) and that users may redistribute the program under\r
+ these conditions, and telling the user how to view a copy of this\r
+ License. (Exception: if the Program itself is interactive but\r
+ does not normally print such an announcement, your work based on\r
+ the Program is not required to print an announcement.)\r
+\f\r
+These requirements apply to the modified work as a whole. If\r
+identifiable sections of that work are not derived from the Program,\r
+and can be reasonably considered independent and separate works in\r
+themselves, then this License, and its terms, do not apply to those\r
+sections when you distribute them as separate works. But when you\r
+distribute the same sections as part of a whole which is a work based\r
+on the Program, the distribution of the whole must be on the terms of\r
+this License, whose permissions for other licensees extend to the\r
+entire whole, and thus to each and every part regardless of who wrote it.\r
+\r
+Thus, it is not the intent of this section to claim rights or contest\r
+your rights to work written entirely by you; rather, the intent is to\r
+exercise the right to control the distribution of derivative or\r
+collective works based on the Program.\r
+\r
+In addition, mere aggregation of another work not based on the Program\r
+with the Program (or with a work based on the Program) on a volume of\r
+a storage or distribution medium does not bring the other work under\r
+the scope of this License.\r
+\r
+ 3. You may copy and distribute the Program (or a work based on it,\r
+under Section 2) in object code or executable form under the terms of\r
+Sections 1 and 2 above provided that you also do one of the following:\r
+\r
+ a) Accompany it with the complete corresponding machine-readable\r
+ source code, which must be distributed under the terms of Sections\r
+ 1 and 2 above on a medium customarily used for software interchange; or,\r
+\r
+ b) Accompany it with a written offer, valid for at least three\r
+ years, to give any third party, for a charge no more than your\r
+ cost of physically performing source distribution, a complete\r
+ machine-readable copy of the corresponding source code, to be\r
+ distributed under the terms of Sections 1 and 2 above on a medium\r
+ customarily used for software interchange; or,\r
+\r
+ c) Accompany it with the information you received as to the offer\r
+ to distribute corresponding source code. (This alternative is\r
+ allowed only for noncommercial distribution and only if you\r
+ received the program in object code or executable form with such\r
+ an offer, in accord with Subsection b above.)\r
+\r
+The source code for a work means the preferred form of the work for\r
+making modifications to it. For an executable work, complete source\r
+code means all the source code for all modules it contains, plus any\r
+associated interface definition files, plus the scripts used to\r
+control compilation and installation of the executable. However, as a\r
+special exception, the source code distributed need not include\r
+anything that is normally distributed (in either source or binary\r
+form) with the major components (compiler, kernel, and so on) of the\r
+operating system on which the executable runs, unless that component\r
+itself accompanies the executable.\r
+\r
+If distribution of executable or object code is made by offering\r
+access to copy from a designated place, then offering equivalent\r
+access to copy the source code from the same place counts as\r
+distribution of the source code, even though third parties are not\r
+compelled to copy the source along with the object code.\r
+\f\r
+ 4. You may not copy, modify, sublicense, or distribute the Program\r
+except as expressly provided under this License. Any attempt\r
+otherwise to copy, modify, sublicense or distribute the Program is\r
+void, and will automatically terminate your rights under this License.\r
+However, parties who have received copies, or rights, from you under\r
+this License will not have their licenses terminated so long as such\r
+parties remain in full compliance.\r
+\r
+ 5. You are not required to accept this License, since you have not\r
+signed it. However, nothing else grants you permission to modify or\r
+distribute the Program or its derivative works. These actions are\r
+prohibited by law if you do not accept this License. Therefore, by\r
+modifying or distributing the Program (or any work based on the\r
+Program), you indicate your acceptance of this License to do so, and\r
+all its terms and conditions for copying, distributing or modifying\r
+the Program or works based on it.\r
+\r
+ 6. Each time you redistribute the Program (or any work based on the\r
+Program), the recipient automatically receives a license from the\r
+original licensor to copy, distribute or modify the Program subject to\r
+these terms and conditions. You may not impose any further\r
+restrictions on the recipients' exercise of the rights granted herein.\r
+You are not responsible for enforcing compliance by third parties to\r
+this License.\r
+\r
+ 7. If, as a consequence of a court judgment or allegation of patent\r
+infringement or for any other reason (not limited to patent issues),\r
+conditions are imposed on you (whether by court order, agreement or\r
+otherwise) that contradict the conditions of this License, they do not\r
+excuse you from the conditions of this License. If you cannot\r
+distribute so as to satisfy simultaneously your obligations under this\r
+License and any other pertinent obligations, then as a consequence you\r
+may not distribute the Program at all. For example, if a patent\r
+license would not permit royalty-free redistribution of the Program by\r
+all those who receive copies directly or indirectly through you, then\r
+the only way you could satisfy both it and this License would be to\r
+refrain entirely from distribution of the Program.\r
+\r
+If any portion of this section is held invalid or unenforceable under\r
+any particular circumstance, the balance of the section is intended to\r
+apply and the section as a whole is intended to apply in other\r
+circumstances.\r
+\r
+It is not the purpose of this section to induce you to infringe any\r
+patents or other property right claims or to contest validity of any\r
+such claims; this section has the sole purpose of protecting the\r
+integrity of the free software distribution system, which is\r
+implemented by public license practices. Many people have made\r
+generous contributions to the wide range of software distributed\r
+through that system in reliance on consistent application of that\r
+system; it is up to the author/donor to decide if he or she is willing\r
+to distribute software through any other system and a licensee cannot\r
+impose that choice.\r
+\r
+This section is intended to make thoroughly clear what is believed to\r
+be a consequence of the rest of this License.\r
+\f\r
+ 8. If the distribution and/or use of the Program is restricted in\r
+certain countries either by patents or by copyrighted interfaces, the\r
+original copyright holder who places the Program under this License\r
+may add an explicit geographical distribution limitation excluding\r
+those countries, so that distribution is permitted only in or among\r
+countries not thus excluded. In such case, this License incorporates\r
+the limitation as if written in the body of this License.\r
+\r
+ 9. The Free Software Foundation may publish revised and/or new versions\r
+of the General Public License from time to time. Such new versions will\r
+be similar in spirit to the present version, but may differ in detail to\r
+address new problems or concerns.\r
+\r
+Each version is given a distinguishing version number. If the Program\r
+specifies a version number of this License which applies to it and "any\r
+later version", you have the option of following the terms and conditions\r
+either of that version or of any later version published by the Free\r
+Software Foundation. If the Program does not specify a version number of\r
+this License, you may choose any version ever published by the Free Software\r
+Foundation.\r
+\r
+ 10. If you wish to incorporate parts of the Program into other free\r
+programs whose distribution conditions are different, write to the author\r
+to ask for permission. For software which is copyrighted by the Free\r
+Software Foundation, write to the Free Software Foundation; we sometimes\r
+make exceptions for this. Our decision will be guided by the two goals\r
+of preserving the free status of all derivatives of our free software and\r
+of promoting the sharing and reuse of software generally.\r
+\r
+ NO WARRANTY\r
+\r
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\r
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\r
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\r
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\r
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\r
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\r
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\r
+REPAIR OR CORRECTION.\r
+\r
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\r
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\r
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\r
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\r
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\r
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\r
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\r
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\r
+POSSIBILITY OF SUCH DAMAGES.\r
+\r
+ END OF TERMS AND CONDITIONS\r
+\f\r
+ Appendix: How to Apply These Terms to Your New Programs\r
+\r
+ If you develop a new program, and you want it to be of the greatest\r
+possible use to the public, the best way to achieve this is to make it\r
+free software which everyone can redistribute and change under these terms.\r
+\r
+ To do so, attach the following notices to the program. It is safest\r
+to attach them to the start of each source file to most effectively\r
+convey the exclusion of warranty; and each file should have at least\r
+the "copyright" line and a pointer to where the full notice is found.\r
+\r
+ <one line to give the program's name and a brief idea of what it does.>\r
+ Copyright (C) 19yy <name of author>\r
+\r
+ This program is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA\r
+\r
+Also add information on how to contact you by electronic and paper mail.\r
+\r
+If the program is interactive, make it output a short notice like this\r
+when it starts in an interactive mode:\r
+\r
+ Gnomovision version 69, Copyright (C) 19yy name of author\r
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\r
+ This is free software, and you are welcome to redistribute it\r
+ under certain conditions; type `show c' for details.\r
+\r
+The hypothetical commands `show w' and `show c' should show the appropriate\r
+parts of the General Public License. Of course, the commands you use may\r
+be called something other than `show w' and `show c'; they could even be\r
+mouse-clicks or menu items--whatever suits your program.\r
+\r
+You should also get your employer (if you work as a programmer) or your\r
+school, if any, to sign a "copyright disclaimer" for the program, if\r
+necessary. Here is a sample; alter the names:\r
+\r
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program\r
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.\r
+\r
+ <signature of Ty Coon>, 1 April 1989\r
+ Ty Coon, President of Vice\r
+\r
+This General Public License does not permit incorporating your program into\r
+proprietary programs. If your program is a subroutine library, you may\r
+consider it more useful to permit linking proprietary applications with the\r
+library. If this is what you want to do, use the GNU Library General\r
+Public License instead of this License.\r
--- /dev/null
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97
+ Free Software Foundation, Inc.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+\f
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+ Ditto for AIX 3.2 and <stdlib.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#include <unistd.h>
+#endif /* GNU C library. */
+
+#ifdef VMS
+#include <unixlib.h>
+#if HAVE_STRING_H - 0
+#include <string.h>
+#endif
+#endif
+
+#if defined (WIN32) && !defined (__CYGWIN32__)
+/* It's not Unix, really. See? Capital letters. */
+#include <windows.h>
+#define getpid() GetCurrentProcessId()
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+ When compiling libc, the _ macro is predefined. */
+#ifdef HAVE_LIBINTL_H
+# include <libintl.h>
+# define _(msgid) gettext (msgid)
+#else
+# define _(msgid) (msgid)
+#endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* 1003.2 says this must be 1 before any call. */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+ causes problems with re-calling getopt as programs generally don't
+ know that. */
+
+int __getopt_initialized = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return -1 with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable. */
+static char *posixly_correct;
+\f
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it. */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+ That was relevant to code that was here before. */
+#if !defined (__STDC__) || !__STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+ and has done so at least since version 2.4.5. -- rms. */
+extern int strlen (const char *);
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+\f
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+ indicating ARGV elements that should not be considered arguments. */
+
+/* Defined in getopt_init.c */
+extern char *__getopt_nonoption_flags;
+
+static int nonoption_flags_max_len;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+extern pid_t __libc_pid;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+ is valid for the getopt call we must make sure that the ARGV passed
+ to getopt is that one passed to the process. */
+static void
+__attribute__ ((unused))
+store_args_and_env (int argc, char *const *argv)
+{
+ /* XXX This is no good solution. We should rather copy the args so
+ that we can compare them later. But we must not use malloc(3). */
+ original_argc = argc;
+ original_argv = argv;
+}
+text_set_element (__libc_subinit, store_args_and_env);
+
+# define SWAP_FLAGS(ch1, ch2) \
+ if (nonoption_flags_len > 0) \
+ { \
+ char __tmp = __getopt_nonoption_flags[ch1]; \
+ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \
+ __getopt_nonoption_flags[ch2] = __tmp; \
+ }
+#else /* !_LIBC */
+# define SWAP_FLAGS(ch1, ch2)
+#endif /* _LIBC */
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+#if defined (__STDC__) && __STDC__
+static void exchange (char **);
+#endif
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+#ifdef _LIBC
+ /* First make sure the handling of the `__getopt_nonoption_flags'
+ string can work normally. Our top argument must be in the range
+ of the string. */
+ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
+ {
+ /* We must extend the array. The user plays games with us and
+ presents new arguments. */
+ char *new_str = malloc (top + 1);
+ if (new_str == NULL)
+ nonoption_flags_len = nonoption_flags_max_len = 0;
+ else
+ {
+ memcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len);
+ memset (&new_str[nonoption_flags_max_len], '\0',
+ top + 1 - nonoption_flags_max_len);
+ nonoption_flags_max_len = top + 1;
+ __getopt_nonoption_flags = new_str;
+ }
+ }
+#endif
+
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
+
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[top - (middle - bottom) + i];
+ argv[top - (middle - bottom) + i] = tem;
+ SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
+ }
+ /* Exclude the moved bottom segment from further swapping. */
+ top -= len;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[middle + i];
+ argv[middle + i] = tem;
+ SWAP_FLAGS (bottom + i, middle + i);
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made. */
+
+#if defined (__STDC__) && __STDC__
+static const char *_getopt_initialize (int, char *const *, const char *);
+#endif
+static const char *
+_getopt_initialize (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ /* Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ first_nonopt = last_nonopt = optind;
+
+ nextchar = NULL;
+
+ posixly_correct = getenv ("POSIXLY_CORRECT");
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (posixly_correct != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+
+#ifdef _LIBC
+ if (posixly_correct == NULL
+ && argc == original_argc && argv == original_argv)
+ {
+ if (nonoption_flags_max_len == 0)
+ {
+ if (__getopt_nonoption_flags == NULL
+ || __getopt_nonoption_flags[0] == '\0')
+ nonoption_flags_max_len = -1;
+ else
+ {
+ const char *orig_str = __getopt_nonoption_flags;
+ int len = nonoption_flags_max_len = strlen (orig_str);
+ if (nonoption_flags_max_len < argc)
+ nonoption_flags_max_len = argc;
+ __getopt_nonoption_flags =
+ (char *) malloc (nonoption_flags_max_len);
+ if (__getopt_nonoption_flags == NULL)
+ nonoption_flags_max_len = -1;
+ else
+ {
+ memcpy (__getopt_nonoption_flags, orig_str, len);
+ memset (&__getopt_nonoption_flags[len], '\0',
+ nonoption_flags_max_len - len);
+ }
+ }
+ }
+ nonoption_flags_len = nonoption_flags_max_len;
+ }
+ else
+ nonoption_flags_len = 0;
+#endif
+
+ return optstring;
+}
+\f
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns -1.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ optarg = NULL;
+
+ if (optind == 0 || !__getopt_initialized)
+ {
+ if (optind == 0)
+ optind = 1; /* Don't scan ARGV[0], the program name. */
+ optstring = _getopt_initialize (argc, argv, optstring);
+ __getopt_initialized = 1;
+ }
+
+ /* Test whether ARGV[optind] points to a non-option argument.
+ Either it does not have option syntax, or there is an environment flag
+ from the shell indicating it is not an option. The later information
+ is only used when the used in the GNU libc. */
+#ifdef _LIBC
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \
+ || (optind < nonoption_flags_len \
+ && __getopt_nonoption_flags[optind] == '1'))
+#else
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+ moved back by the user (who may also have changed the arguments). */
+ if (last_nonopt > optind)
+ last_nonopt = optind;
+ if (first_nonopt > optind)
+ first_nonopt = optind;
+
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc && NONOPTION_P)
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* The special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return -1;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if (NONOPTION_P)
+ {
+ if (ordering == REQUIRE_ORDER)
+ return -1;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Skip the initial punctuation. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ /* Decode the current option-ARGV-element. */
+
+ /* Check whether the ARGV-element is a long option.
+
+ If long_only and the ARGV-element has the form "-f", where f is
+ a valid short option, don't consider it an abbreviated form of
+ a long option that starts with f. Otherwise there would be no
+ way to give the -f short option.
+
+ On the other hand, if there's a long option "fubar" and
+ the ARGV-element is "-fu", do consider that an abbreviation of
+ the long option, just like "--fu", and not "-f" with arg "u".
+
+ This distinction seems to be the most useful approach. */
+
+ if (longopts != NULL
+ && (argv[optind][1] == '-'
+ || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = -1;
+ int option_index;
+
+ for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar)
+ == (unsigned int) strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ optopt = 0;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (opterr)
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ _("%s: option `--%s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ _("%s: option `%c%s' doesn't allow an argument\n"),
+ argv[0], argv[optind - 1][0], pfound->name);
+
+ nextchar += strlen (nextchar);
+
+ optopt = pfound->val;
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ optopt = pfound->val;
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ optopt = 0;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next short option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+ if (posixly_correct)
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, _("%s: illegal option -- %c\n"),
+ argv[0], c);
+ else
+ fprintf (stderr, _("%s: invalid option -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ return '?';
+ }
+ /* Convenience. Treat POSIX -W foo same as long option --foo */
+ if (temp[0] == 'W' && temp[1] == ';')
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = 0;
+ int option_index;
+
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ return c;
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+
+ /* optarg is now the argument, see if it's in the
+ table of longopts. */
+
+ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar) == strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (opterr)
+ fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ nextchar = NULL;
+ return 'W'; /* Let the application handle it. */
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = NULL;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr,
+ _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* Not ELIDE_CODE. */
+\f
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
--- /dev/null
+/* Declarations for getopt.
+ Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if defined (__STDC__) && __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+//#if defined (__STDC__) && __STDC__
+//#ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+//#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+//#endif /* __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+//#else /* not __STDC__ */
+//extern int getopt ();
+//extern int getopt_long ();
+//extern int getopt_long_only ();
+
+//extern int _getopt_internal ();
+//#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
--- /dev/null
+/*\r
+ pushpins.cpp\r
+\r
+ Extract data from MS Streets & Trips .est and Autoroute .axe files in GPX format.\r
+\r
+ Copyright (C) 2003 James Sherring, james_sherring@yahoo.com\r
+\r
+ This program is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA\r
+*/\r
+\r
+#import "c:\program files\common files\system\ado\msado15.dll" rename ( "EOF", "adoEOF" )\r
+//#import <msado15.dll> rename ( "EOF", "adoEOF" )\r
+\r
+#include <windows.h>\r
+#include <initguid.h> // Include only once in your application\r
+//#include "adoid.h" // ADO GUID's\r
+//#include "adoint.h" // ADO Classes, enums, etc.\r
+#include <oleauto.h> // for sysstringlength\r
+#include <stdio.h>\r
+//#include <stdlib.h>\r
+//#include <malloc.h>\r
+//#include <memory.h>\r
+#include <string.h>\r
+\r
+#include "pushpins.h"\r
+\r
+struct InitOle {\r
+InitOle() { ::CoInitialize(NULL); }\r
+~InitOle() { ::CoUninitialize(); }\r
+} _init_InitOle_;\r
+\r
+int verbose_flag;\r
+\r
+void * xmalloc(size_t size)\r
+{\r
+ void *obj = malloc(size);\r
+ if (!obj)\r
+ {\r
+ fprintf(stderr, "Unable to allocate %d bytes of memory.\n", size);\r
+ }\r
+ return obj;\r
+}\r
+\r
+LPWSTR wstr2cpy(BSTR wstr)\r
+{\r
+ int len=wcslen(wstr);\r
+ LPWSTR newstr=(LPWSTR)xmalloc((len+1)*sizeof(WCHAR));\r
+ wcscpy(newstr, wstr);\r
+ return newstr;\r
+}\r
+\r
+char* wstr2str(BSTR wstr)\r
+// there must be a better way to do this\r
+{\r
+ int len;\r
+ int i;\r
+ char* newstr=NULL;\r
+ // call to get length\r
+ len = WideCharToMultiByte(\r
+ CP_THREAD_ACP,\r
+ 0,\r
+ wstr,\r
+ -1,\r
+ newstr,\r
+ 0, \r
+ NULL,\r
+ 0);\r
+ if(len==0)\r
+ {\r
+ //printf("wide2normal got length %d\n", len);\r
+ len=wcslen(wstr);\r
+ //printf("wide2normal cheated and got length %d\n", len);\r
+ };\r
+ newstr = (char*)xmalloc((len+1)*sizeof(char));\r
+ // now call to set string\r
+ len = WideCharToMultiByte(\r
+ CP_THREAD_ACP,\r
+ 0,\r
+ wstr,\r
+ -1,\r
+ newstr,\r
+ len, \r
+ NULL,\r
+ 0);\r
+ //printf("wide2normal copied %d chars and got string %s\n", len, newstr);\r
+ if (len==0)\r
+ {\r
+ len=wcslen(wstr);\r
+ for(i=0; i<len; i++)\r
+ newstr[i]=wstr[i];\r
+ newstr[len]=0;\r
+ //printf("wide2normal cheated to get string %s\n", newstr);\r
+ }\r
+ return newstr;\r
+}\r
+\r
+void readfield(VARIANT vt_val, unsigned short fieldtype, void* stor_var)\r
+{\r
+// int len=0;\r
+ LPWSTR tempwstr=NULL;\r
+ char* shortstr=NULL;\r
+// int status;\r
+// int i;\r
+\r
+ if ((vt_val.vt == fieldtype) || ( (fieldtype==VT_BSTR) && (vt_val.vt==VT_NULL)))\r
+ {\r
+ switch (vt_val.vt)\r
+ {\r
+ case VT_I4:\r
+ *(long*)stor_var = vt_val.lVal;\r
+ break;\r
+\r
+ case VT_I2:\r
+ *(int*)stor_var = vt_val.iVal;\r
+ break;\r
+\r
+ case VT_BSTR:\r
+ // FIXME handle bstr properly\r
+ tempwstr = wstr2cpy(vt_val.bstrVal);\r
+ //wprintf(L"got temp str%s\n",tempwstr);\r
+\r
+ shortstr = wstr2str(vt_val.bstrVal);\r
+ //printf("got short temp str%s\n",shortstr);\r
+ \r
+ //*(void**)stor_var = (void*)tempwstr;\r
+ *(char**)stor_var = shortstr;\r
+ //printf("verified short temp str%s\n", *(char**)stor_var);\r
+ break;\r
+\r
+ case VT_NULL:\r
+ // expected string, this is null \r
+ // so return empty string\r
+\r
+ shortstr = (char*)xmalloc(sizeof(char));\r
+ shortstr[0]=0;\r
+ //printf("got short temp str%s\n",shortstr);\r
+ \r
+ *(char**)stor_var = shortstr;\r
+ break;\r
+ default:\r
+ fprintf(stderr,"Unsupported type, unable to read from DB\n");\r
+ }\r
+\r
+ }\r
+ else\r
+ {\r
+ fprintf(stderr,"Type mismatch when reading from DB, expected type %d read type %d\n", \r
+ fieldtype, vt_val.vt);\r
+ }\r
+\r
+}\r
+\r
+// EXTERN_C \r
+EXTERN_C void read_ppin_list(char* ppin_file_name)\r
+{\r
+\r
+ struct pushpin * ppin;\r
+ int ppinnum=0;\r
+ \r
+ try \r
+ {\r
+ HRESULT hr = S_OK;\r
+ ADODB::_RecordsetPtr rs; \r
+ char cnstr[500];\r
+ char sqlstr[] = "SELECT UD_Secondary.UdId, UD_Secondary.UdName, UD_Secondary.NoteShort, UD_Secondary.NoteLong, UD_Main.Grid, UD_Main.Precision FROM UD_Main INNER JOIN UD_Secondary ON UD_Main.UdId = UD_Secondary.UdId";\r
+ sprintf(cnstr, "PROVIDER=Microsoft.Jet.OLEDB.4.0;data source=%s; Jet OLEDB:Database Password=Geo80;", ppin_file_name);\r
+\r
+ hr = rs.CreateInstance( __uuidof( ADODB::Recordset ) );\r
+ hr = rs->Open(sqlstr, \r
+ cnstr, \r
+ ADODB::adOpenForwardOnly, \r
+ ADODB::adLockReadOnly, \r
+ -1 );\r
+ hr = rs->MoveFirst();\r
+ while ((rs->adoEOF == FALSE))\r
+ {\r
+ ppin = (struct pushpin *)xmalloc(sizeof(struct pushpin));\r
+\r
+ readfield(rs->Fields->GetItem("UdId")->Value, VT_I4, &(ppin->UdId));\r
+ readfield(rs->Fields->GetItem("UdName")->Value, VT_BSTR,&(ppin->UdName));\r
+ readfield(rs->Fields->GetItem("Grid")->Value, VT_I4, &(ppin->Grid));\r
+ readfield(rs->Fields->GetItem("Precision")->Value, VT_I4, &(ppin->Precision));\r
+ readfield(rs->Fields->GetItem("NoteShort")->Value, VT_BSTR,&(ppin->NoteShort));\r
+\r
+ if (verbose_flag > 3)\r
+ printf("Read pushpin UdId=%d, UdName=%s, Grid=%d, Precision=%d, NoteShort=%s\n", \r
+ ppin->UdId, ppin->UdName, \r
+ ppin->Grid, ppin->Precision, ppin->NoteShort);\r
+\r
+ ppin_list[ppinnum]=ppin;\r
+ ppinnum++;\r
+ if (ppinnum>MAX_PUSHPINS-1)\r
+ {\r
+ printf("Exceeded maximun number of pushpins (I should fix this)\n");\r
+ break;\r
+ }\r
+\r
+ hr = rs->MoveNext();\r
+ }\r
+ hr = rs->Close();\r
+ rs = NULL;\r
+ }\r
+ catch( _com_error &e)\r
+ {\r
+ _bstr_t bstrSource(e.Source());\r
+ _bstr_t bs = _bstr_t(" Error: ") + _bstr_t(e.Error()) + _bstr_t(" Msg: ") \r
+ + _bstr_t(e.ErrorMessage()) + _bstr_t(" Description: ") \r
+ + _bstr_t(e.Description());\r
+ \r
+ MessageBox(0,bs,bstrSource, MB_OK);\r
+ } \r
+}\r
--- /dev/null
+/*\r
+ pushpins.h\r
+\r
+ Extract data from MS Streets & Trips .est and Autoroute .axe files in GPX format.\r
+\r
+ Copyright (C) 2003 James Sherring, james_sherring@yahoo.com\r
+\r
+ This program is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA\r
+\r
+*/\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#define MAX_PUSHPINS 5000\r
+\r
+// max size to be read from ppin memo fields\r
+#define MAX_PPIN_MEMO 1000\r
+\r
+typedef struct pushpin\r
+{\r
+ long UdId;\r
+ int SetId;\r
+ long Grid;\r
+ long Precision;\r
+// dword RenderData;\r
+// byte MatchId;\r
+// long MOBBId;\r
+// long SourceUdId;\r
+// bool IsTerritory;\r
+//\r
+ char* UdName; // max 128\r
+// bool NoNameSearch;\r
+// byte NoteTypeId;\r
+ char* NoteShort; // max 255\r
+// char* NoteLong; // memo\r
+// char* GeocodeShort; // max 255\r
+// char* GeocodeLong; // memo\r
+// byte GeocodeHierarchy; \r
+// byte GeocodeContext; \r
+// OLE Object EntityArray ????\r
+//\r
+// shouldn't include these two here because they are not part of the native pushpin definition\r
+ double lat;\r
+ double lon;\r
+} tag_pushpin;\r
+\r
+\r
+typedef struct pushpinset\r
+{\r
+ int SetId;\r
+ char* SetName; // max 128\r
+/* byte RenderMethod;\r
+ byte GeocodeMethod;\r
+ byte CreateMethod;\r
+ byte GeometryType;\r
+ char[128] RenderData;\r
+ long UdCount;\r
+ long MatchedCount;\r
+ long SkippedCount;\r
+ long UnmatchedCount;\r
+ long CounterUpdateMask;\r
+ int ParentSetId;\r
+ bool IsRendered;\r
+ long Z_Order;\r
+ long GeocodeCtxt;\r
+ OLE Object ThemeRenderData\r
+ date/time LastGeocoded\r
+ char* DataSrcDescr; // memo\r
+ char[30] CurrencyData;\r
+*/\r
+} tag_pushpinset;\r
+\r
+//struct pushpin * ppin_list[MAX_PUSHPINS];\r
+struct pushpin * ppin_list[5000];\r
+\r
+//EXTERN_C\r
+ void read_ppin_list(char* ppin_file_name);\r
+\r
+\r
+#ifdef __cplusplus\r
+} /* closing brace for extern "C" */\r
+#endif\r
--- /dev/null
+/*\r
+ st2gpxmain.c\r
+\r
+ Extract data from MS Streets & Trips .est and Autoroute .axe files in GPX format.\r
+\r
+ Copyright (C) 2003 James Sherring, james_sherring@yahoo.com\r
+\r
+ This program is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA\r
+\r
+\r
+History:\r
+\r
+21-10-2003 annotations stream dump\r
+27-10-2003 journey & pushpins using VB module\r
+ 8-11-2003 match journey route-points to pushpins,\r
+ integrate parts into singel C/C++ exe (except istorage)\r
+ 9-11-2003 fixed invalid gpx\r
+\r
+To do:\r
+ Get lat & lon for journey route points not matched to pushpins\r
+ Get point info for non-line annotations, e.g. text boxes.\r
+ Import functionality\r
+ Implement using platform independant libraries.\r
+\r
+bugs:\r
+ unable to delete UserData file after accessing with ADO.\r
+*/\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <malloc.h>\r
+#include <memory.h>\r
+#include <math.h>\r
+#include <string.h>\r
+\r
+// #include <getopt.h>\r
+#include "getopt.h"\r
+#include "pushpins.h"\r
+\r
+#ifndef M_PI\r
+#define M_PI 3.1415926535\r
+#endif\r
+\r
+#define JOUR_FILE_HEAD_LEN 32\r
+#define JOUR_FILE_TAIL_LEN 430\r
+// + text1 +2*text2\r
+#define JOUR_WPTREC_LEN 121\r
+\r
+#define JOUR_FILEOS_NUMREC 16\r
+\r
+#define JOURWPT_REC_HEAD_LEN 41\r
+\r
+#define JOURWPT_RECOS_WPTNUM 0\r
+#define JOURWPT_RECOS_STR1LEN 40\r
+#define JOURWPT_RECOS_STR1 41\r
+// + val(JOURWPT_RECOS_STR1LEN)\r
+#define JOURWPT_RECOS_STR2LEN 44\r
+#define JOURWPT_RECOS_STR2 45\r
+\r
+#define ANNOT_FILE_HEAD_LEN 12\r
+// This needs to be long enough to get enough params to decide which record,\r
+// but no biger than the shortest record\r
+#define ANNOT_REC_HEAD_LEN 57 //19\r
+\r
+#define ANNOT_TYPE_LINE 0\r
+#define ANNOT_TYPE_OVAL 1\r
+#define ANNOT_TYPE_TEXT 2\r
+#define ANNOT_TYPE_CIRCLE 3\r
+\r
+#define REC_CLOSE_LEN 0\r
+// offsets for parameters in annotation recods\r
+#define ANNOT_RECOS_TYPE 0\r
+#define ANNOT_RECOS_ANUM 4\r
+#define ANNOT_RECOS_TEXTLEN 20\r
+#define ANNOT_RECOS_TEXT 24\r
+#define ANNOT_RECOS_LINENUMPOINTS 53\r
+#define ANNOT_RECOS_LINEJOINFLAG 48\r
+#define ANNOT_RECOS_XSCALE 48\r
+#define ANNOT_RECOS_YSCALE 52\r
+\r
+#define GPX_HEADER1 "<?xml version=\"1.0\" standalone=\"yes\"?>\n<gpx version=\"1.0\" \n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n xmlns=\"http://www.topografix.com/GPX/1/0\"\n xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\"\n "\r
+#define GPX_HEADER2 " creator=\"st2gpx-james_sherring@yahoo.com\">\n"\r
+#define GPX_THIS_PROGRAM "st2gpx from james_sherring@yahoo.com"\r
+#define GPX_FOOTER "</gpx>"\r
+\r
+#define GPX_WPT 0\r
+#define GPX_RTEPT 1\r
+#define GPX_TRKPT 2\r
+\r
+/*\r
+typedef struct annotationbuf\r
+{\r
+ int annot_num;\r
+ int flags; // bit fields in first byte\r
+ int unkn1; // normally 0\r
+ int unkn2; // ? seems to have byte fields\r
+ int text_len;\r
+ // + 2*text_len bytes of text here\r
+ int fill_color; // seems to have byte fields. First byte is fill, other bytes are strange\r
+ int line_color;\r
+ int line_thickness; // 20 times the point-size\r
+ int arrow_type; // 00=none, 01=left, 02=right, 03=both\r
+ int unkn3;\r
+ int joinflag; // 0 line does not join, 1, joins. Not sure what large balues for non-lines mean - xscale?\r
+ char unkn4; // y-scale?\r
+ int num_points; // different meaning for non-lines\r
+} structannotationbuf;\r
+*/\r
+\r
+typedef struct jourwpt_rec\r
+{\r
+ int jour_num;\r
+ int text1_length;\r
+ char* text1;\r
+ int text2_length;\r
+ char* text2;\r
+ long UdId;\r
+ struct pushpin* pushpin;\r
+ int buf_length;\r
+ char* buf;\r
+} tag_jour_rec;\r
+\r
+typedef struct gpx_point\r
+{\r
+ float lat;\r
+ float lon;\r
+ float height;\r
+} tag_gpx_point;\r
+\r
+typedef char* annot_file_header;\r
+typedef char* annot_rec_header;\r
+typedef char* annot_buf;\r
+\r
+typedef struct annot_rec\r
+{\r
+ int type;\r
+ int length;\r
+ char* buf;\r
+ int annot_num;\r
+ int text_length;\r
+ char* text;\r
+ int line_points;\r
+} tag_annot_rec;\r
+\r
+struct point {\r
+ double lon;\r
+ double lat;\r
+} tag_point;\r
+\r
+struct ms_point {\r
+ long grid;\r
+ long precision;\r
+} tag_ms_point;\r
+\r
+\r
+// Also need to include variable text length + line-points with these\r
+int annot_rec_len[4]={57, 868, 124, 868};\r
+int annot_head_len[4]={57, 48, 48, 48};\r
+char* annot_type_name[4]={"Line", "Oval", "Textbox", "Circle"};\r
+static char* gpxptypelabel[] = {"wpt", "rtept", "trkpt"};\r
+\r
+// constants for converting from MS Grid & Precision to latitude and longitude\r
+double magic1 = 182.044444444444;\r
+double magic2 = 0x10000;\r
+\r
+// Args set by getopt etc\r
+\r
+FILE* ppin_file=NULL;\r
+FILE* jour_file=NULL;\r
+FILE* annot_file=NULL;\r
+FILE* gpx_file=NULL;\r
+char* source_file_name=NULL;\r
+\r
+/* Flag set by --verbose. */\r
+// 0 - only errors\r
+// 1 also the structured data output, e.g. line point info\r
+// 2 also record types & parameters\r
+// 3 also detailed summary info\r
+// 4 also detailed analysis of headers & record params\r
+// 5 also dump buffers\r
+// 6 lots of debug info\r
+static int verbose_flag = 2;\r
+static int explore_flag = 0;\r
+// force line-type annotations to be exported as GPX routes instead of tracks\r
+static int use_gpx_route = 0;\r
+\r
+// std_anotfile_header[8,9] are variable (number of annotations)\r
+char std_annotfile_header[ANNOT_FILE_HEAD_LEN] =\r
+ {0x34, 0x12, 0x00, 0x2d, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00};\r
+\r
+void * xmalloc(size_t size)\r
+{\r
+ void *obj = malloc(size);\r
+ if (!obj)\r
+ {\r
+ fprintf(stderr, "Unable to allocate %d bytes of memory.\n", size);\r
+ }\r
+ return obj;\r
+}\r
+\r
+void * xrealloc(void* ptr, size_t size)\r
+{\r
+ void *obj = realloc(ptr, size);\r
+ if (!obj)\r
+ {\r
+ fprintf(stderr, "Unable to (re)allocate %d bytes of memory.\n", size);\r
+ }\r
+ return obj;\r
+}\r
+\r
+int fixhex(char c)\r
+{\r
+// gcc (version?) does not print single byte hex vaues properly\r
+// eg 0xe3 prints as 0xFFFFFFE3\r
+// this is only a problem for values above 0x80\r
+// Or maybe that is the proper handling of unsigned?\r
+// Aaaahhh. I should use %u for printing unsigned... but the hex problem is still there\r
+ if(c & 0x80)\r
+ {\r
+ return ((int)c-0xFFFFFF00);\r
+ } else\r
+ return c;\r
+}\r
+\r
+void printbuf(char* buf, int len)\r
+{\r
+// unsigned i;\r
+ int i;\r
+ printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");\r
+ printf(" -----------------------------------------------");\r
+ for(i=0; i<len; i++)\r
+ {\r
+ if (((i+1) & 0x0f) == 0x1)\r
+ printf("\n%2x| ",i/16);\r
+ printf("%2x ",fixhex(buf[i]));\r
+ }\r
+ printf("\n\n");\r
+}\r
+\r
+void printbufwide(char* buf, int len)\r
+{\r
+ int i;\r
+ for(i=0; i<len; i++)\r
+ {\r
+ printf("%2x ",fixhex(buf[i]));\r
+ }\r
+ printf("\n\n");\r
+}\r
+\r
+void printbufhigh(char* buf, int len)\r
+{\r
+ int i;\r
+ for(i=0; i<len; i++)\r
+ {\r
+ printf("%02x %02x\n", i, fixhex(buf[i]));\r
+ }\r
+ printf("\n\n");\r
+}\r
+\r
+void printbufasfloat(char* buf, int len)\r
+{\r
+// unsigned i;\r
+ int i;\r
+// printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");\r
+// printf(" -----------------------------------------------");\r
+ for(i=0; i<len-3; i++)\r
+ {\r
+ if (((i+1) & 0x03) == 0x1)\r
+ printf("\n%2x| ",i);\r
+ printf("%f ", *(float*)(buf+i));\r
+ fflush(stdout);\r
+ }\r
+ printf("\n\n");\r
+}\r
+\r
+void printfloatbuf(float* fbuf, int len)\r
+{\r
+// unsigned i;\r
+ int i;\r
+// printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");\r
+// printf(" -----------------------------------------------");\r
+ for(i=0; i<len; i++)\r
+ {\r
+ if (((i+1) & 0x03) == 0x1)\r
+ printf("\n%2x| ",4*i);\r
+ printf("%f ", fbuf[i]);\r
+ fflush(stdout);\r
+ }\r
+ printf("\n\n");\r
+}\r
+\r
+struct gpx_point gpx_get_point(char* buf)\r
+{\r
+// need to be sure this is done with double precision\r
+ struct gpx_point pt;\r
+ double x;\r
+ double y;\r
+ double z;\r
+\r
+ x= *(float *)(buf);\r
+ y= *(float *)(buf + 4);\r
+ z= *(float *)(buf + 8);\r
+\r
+ //printf("gpx_get_point x=%f y=%f z=%f\n",x,y,z);\r
+ pt.lat = atan2(z,sqrt(pow(x,2)+ pow(y,2)))*180/M_PI;\r
+ pt.lon = atan2(y,x)*180/M_PI;\r
+ // 6378137 is earths equatorial radius in meters\r
+ pt.height = (sqrt(pow(x,2)+ pow(y,2)+ pow(z,2))-1)*6378137;\r
+ return pt;\r
+}\r
+\r
+void printpoints(char* buf, int numpts)\r
+{\r
+ int i;\r
+// int j;\r
+ struct gpx_point pt;\r
+ printf("Latitude Longitude Height");\r
+ printf("\n");\r
+ printf("--------------------------\n");\r
+ for(i=0; i<numpts; i++)\r
+ {\r
+ pt = gpx_get_point(buf + 12*i);\r
+ printf("%f %f %f \n",pt.lat, pt.lon, pt.height);\r
+ }\r
+ printf("\n\n");\r
+}\r
+\r
+void printpointsbuf(char* buf, int len)\r
+{\r
+// unsigned i;\r
+// unsigned j;\r
+ int i;\r
+ int j;\r
+ printf(" 0 1 2 3 4 5 6 7 8 9 A B\n");\r
+ printf(" -----------------------------------");\r
+ for(i=0; i<len; i++)\r
+ {\r
+ printf("\n%2x| ",i);\r
+ // printf("\n");\r
+ for (j=0; j<12; j++)\r
+ {\r
+ printf("%2x ",fixhex(buf[12*i+j]));\r
+ fflush(stdout);\r
+ }\r
+ }\r
+ printf("\n\n");\r
+}\r
+\r
+void printbufaspoints(char* buf, int buflen)\r
+{\r
+ int i;\r
+// int j;\r
+ struct gpx_point pt;\r
+ printf("Latitude Longitude Height");\r
+ printf("\n");\r
+ printf("--------------------------\n");\r
+ for(i=0; i<buflen-11; i++)\r
+ {\r
+ pt = gpx_get_point(buf + 12*i);\r
+ printf("%#02x %f N %f E %f m \n", i, pt.lat, pt.lon, pt.height);\r
+ fflush(stdout);\r
+ }\r
+ printf("\n\n");\r
+}\r
+\r
+void printnzbuf(char* buf, int len)\r
+{\r
+// print non-zero values in the buffer\r
+// unsigned i;\r
+ int i;\r
+ for(i=0; i<len; i++)\r
+ {\r
+// if (buf[i] != 0) printf("Buf[%x]=%2x ",fixhex(i), fixhex(buf[i]));\r
+ if (buf[i] != 0) printf("Buf[%x]=%2x ",i, fixhex(buf[i]));\r
+ }\r
+ printf("\n");\r
+}\r
+\r
+void printnzhead(struct annot_rec rec)\r
+{\r
+ printnzbuf(rec.buf, annot_head_len[rec.type]);\r
+}\r
+\r
+struct point ms2latlong(struct ms_point msp) {\r
+\r
+// grid and precision are the high and low words obtained by interleaving the bits\r
+// of latitude and longitude. There is a scale factor, so that grid represents\r
+// latitude and longitude value parts more than ~ 1/182.0444,\r
+// and precision represents the rest of the values.\r
+\r
+// So we pull each 2n-th bit out, and shift it n places back to the nth longitudinal bit\r
+// and we pull each 2n-th+1 bit out, and shift it n+1 places to the nth latitudinal bit,\r
+\r
+ unsigned long int lat_mask=1;\r
+ unsigned long int lon_mask=2;\r
+ unsigned long int lat_val = 0;\r
+ unsigned long int lon_val = 0;\r
+ struct point p;\r
+\r
+ int i;\r
+ for(i=0; i<16; i++) {\r
+ lat_val += (lat_mask & msp.grid) >> i;\r
+ lon_val += (lon_mask & msp.grid) >> (i+1);\r
+ lat_mask <<= 2;\r
+ lon_mask <<= 2;\r
+ }\r
+\r
+ //printf("so far, lat_val=%d, lon_val=%d\n",lat_val ,lon_val);\r
+\r
+ // Dont divide by magic1 until accounting for precision,\r
+ // because that would introduce rounding errors\r
+ p.lat = (double) lat_val ;// magic1;\r
+ p.lon = (double) lon_val ;// magic1;\r
+\r
+ //printf("so far, got lat= %f lon= %f\n", p.lat, p.lon);\r
+\r
+ lat_mask=1;\r
+ lon_mask=2;\r
+ lat_val=0;\r
+ lon_val=0;\r
+\r
+ for (i=0; i<16; i++) {\r
+ lat_val += (lat_mask & msp.precision) >> i;\r
+ lon_val += (lon_mask & msp.precision) >> (i+1);\r
+ lat_mask <<= 2;\r
+ lon_mask <<= 2;\r
+ }\r
+\r
+ //printf("so far, lat_val=%d, lon_val=%d\n",lat_val ,lon_val);\r
+\r
+ p.lat += (double) lat_val / (magic2);\r
+ p.lon += (double) lon_val / (magic2);\r
+\r
+ p.lat *= 1/ (magic1);\r
+ p.lon *= 1/ (magic1);\r
+\r
+ //printf("so far, got lat= %f lon= %f\n", p.lat, p.lon);\r
+\r
+ if (p.lon > 180) p.lon -= 360;\r
+ if (p.lat > 180) p.lat -= 360;\r
+ return p;\r
+}\r
+\r
+void explore_annot(struct annot_rec rec)\r
+{\r
+ char* header;\r
+ char* tail;\r
+ int taillength;\r
+\r
+ header = (char*)xmalloc(ANNOT_REC_HEAD_LEN);\r
+ memcpy(header, rec.buf, ANNOT_RECOS_TEXT);\r
+ memcpy(header+ANNOT_RECOS_TEXT+2*rec.text_length, rec.buf,\r
+ ANNOT_REC_HEAD_LEN-ANNOT_RECOS_TEXT);\r
+\r
+ tail = rec.buf+ANNOT_REC_HEAD_LEN+2*rec.text_length;\r
+ taillength = rec.length - ANNOT_REC_HEAD_LEN+2*rec.text_length;\r
+\r
+ printf("Record buffer\n", annot_type_name[rec.type]);\r
+ printbuf(rec.buf, rec.length);\r
+ printf("Record high buffer\n", annot_type_name[rec.type]);\r
+ printbufhigh(rec.buf, rec.length);\r
+ printf("Record wide header:\n", annot_type_name[rec.type]);\r
+ printbufwide(header, ANNOT_REC_HEAD_LEN);\r
+ printf("Record tail:\n");\r
+ printbuf(tail, taillength);\r
+ printf("Record wide tail:\n");\r
+ printbufwide(tail, taillength);\r
+ printf("Record tail as floats:\n");\r
+ printbufasfloat(tail, taillength);\r
+ printf("Record tail as points:\n");\r
+ printbufaspoints(tail, taillength);\r
+// if (rec.type == ANNOT_TYPE_TEXT)\r
+// {\r
+ //printfloatbuf((float*)(tail+3), taillength/4 -1);\r
+// }\r
+// else if (rec.type == ANNOT_TYPE_OVAL )\r
+// printfloatbuf((float*)(tail+3), taillength/4 -1);\r
+// else if (rec.type == ANNOT_TYPE_CIRCLE ))\r
+// printfloatbuf((float*)(tail+3), taillength/4 -1);\r
+ free(header);\r
+}\r
+\r
+void gpx_open_write_file_header(char* gpx_file_name)\r
+{\r
+ if (gpx_file_name)\r
+ {\r
+ gpx_file = fopen(gpx_file_name, "w");\r
+ if (gpx_file == NULL)\r
+ {\r
+ fprintf(stderr, "Cannot open %s\n", optarg);\r
+ exit(1);\r
+ }\r
+ }\r
+ else\r
+ return;\r
+\r
+ if (gpx_file!=NULL)\r
+ {\r
+ fprintf(gpx_file, GPX_HEADER1);\r
+ fprintf(gpx_file, GPX_HEADER2);\r
+ if (source_file_name)\r
+ fprintf(gpx_file, "\t<desc>=\"This file was created from %s by %s\"</desc>\n",\r
+ source_file_name, GPX_THIS_PROGRAM);\r
+ // Some more tags we should add here\r
+ // <name> Descriptive name of the GPX file\r
+ // <desc> Description of the GPX file\r
+ // <author> Name of the file's creator\r
+ // <time> Creation date/time of the GPX file\r
+ }\r
+}\r
+\r
+void gpx_write_file_trailer()\r
+{\r
+ if (gpx_file!=NULL)\r
+ {\r
+ fprintf(gpx_file, GPX_FOOTER);\r
+ fclose(gpx_file);\r
+ }\r
+}\r
+\r
+void gpx_write_point(struct gpx_point pt, int pt_type, char* opt_elms)\r
+{\r
+ if (gpx_file!=NULL)\r
+ {\r
+ if (pt_type == GPX_TRKPT)\r
+ fprintf(gpx_file, "\t\t");\r
+ else if (pt_type == GPX_RTEPT)\r
+ fprintf(gpx_file, "\t");\r
+ fprintf(gpx_file, "\t<%s lat=\"%f\" lon=\"%f\">%s</%s>\n",\r
+ gpxptypelabel[pt_type], pt.lat, pt.lon,\r
+ opt_elms, gpxptypelabel[pt_type]);\r
+ }\r
+}\r
+\r
+void gpx_write_jour_point(struct jourwpt_rec * wpt)\r
+{\r
+ struct gpx_point pt;\r
+ char* opt_elms;\r
+ int optlen;\r
+\r
+ if (gpx_file==NULL)\r
+ return;\r
+\r
+ // For now we only deal with journey points which we matched to a pushpin.\r
+ // Later we need to allow for finding lat & lon in the journey stream itself\r
+ if (!wpt->pushpin)\r
+ return;\r
+ //printf("in gpx_write_jour_point\n");\r
+ //fflush(stdout);\r
+\r
+ optlen = strlen(wpt->pushpin->UdName) + strlen(wpt->pushpin->NoteShort) + 40;\r
+ opt_elms = (char*)xmalloc(optlen);\r
+\r
+ //printf("doing sprintf(opt_elms\n");\r
+ //fflush(stdout);\r
+\r
+ sprintf(opt_elms, "<name>%s</name><cmt>%s</cmt>",\r
+ wpt->pushpin->UdName, wpt->pushpin->NoteShort);\r
+\r
+ pt.lat = wpt->pushpin->lat;\r
+ pt.lon = wpt->pushpin->lon;\r
+ pt.height = 0;\r
+\r
+ //printf("doing gpx_write_point\n");\r
+ //fflush(stdout);\r
+\r
+ gpx_write_point(pt, GPX_RTEPT, opt_elms);\r
+\r
+ free(opt_elms);\r
+\r
+ //printf("out of gpx_write_jour_point\n");\r
+ //fflush(stdout);\r
+\r
+}\r
+\r
+void gpx_write_jour_header()\r
+{\r
+ if(gpx_file!=NULL)\r
+ {\r
+ fprintf(gpx_file, "\t<rte>\n");\r
+ fprintf(gpx_file, "\t\t<name>Journey</name>\n");\r
+ fprintf(gpx_file, "\t\t<src>Extracted from main Journey</src>\n");\r
+ }\r
+}\r
+\r
+void gpx_write_jour_trailer()\r
+{\r
+ if(gpx_file!=NULL)\r
+ fprintf(gpx_file, "\t</rte>\n");\r
+\r
+}\r
+\r
+struct pushpin * ppin_by_UdId(int UdId)\r
+{\r
+ int i;\r
+\r
+ //printf("looking to match UdId %d to a pushpin\n", UdId);\r
+ //fflush(stdout);\r
+\r
+ if (UdId == 0)\r
+ return NULL;\r
+\r
+ for (i=0; i< MAX_PUSHPINS; i++)\r
+ {\r
+ //printf("Comparing to pushpin %d\n", i);\r
+ //fflush(stdout);\r
+ if(ppin_list[i] == NULL)\r
+ return NULL;\r
+\r
+ //printf(" with UdId %ld ", (ppin_list[i])->UdId);\r
+ //fflush(stdout);\r
+ //printf(" and name %s\n", (ppin_list[i])->UdName);\r
+\r
+ if ((ppin_list[i]->UdId) == 0)\r
+ return NULL;\r
+\r
+ if (ppin_list[i]->UdId == UdId)\r
+ return ppin_list[i];\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+void gpx_write_pushpinlist ()\r
+{\r
+ int i;\r
+ struct gpx_point pt;\r
+ char* opt_elms;\r
+ int optlen;\r
+\r
+ if (gpx_file==NULL)\r
+ return;\r
+\r
+ for (i=0; i<MAX_PUSHPINS; i++)\r
+ {\r
+ if (ppin_list[i]==NULL)\r
+ break;\r
+\r
+ optlen = strlen(ppin_list[i]->UdName) + strlen(ppin_list[i]->NoteShort) + 40;\r
+ opt_elms = (char*)xmalloc(optlen);\r
+\r
+ sprintf(opt_elms, "<name>%s</name><cmt>%s</cmt>",\r
+ ppin_list[i]->UdName, ppin_list[i]->NoteShort);\r
+\r
+ pt.lat = ppin_list[i]->lat;\r
+ pt.lon = ppin_list[i]->lon;\r
+ pt.height = 0;\r
+\r
+ gpx_write_point(pt, GPX_WPT, opt_elms);\r
+ }\r
+ fprintf(gpx_file, "\n");\r
+}\r
+\r
+void gpx_write_annot_rec(struct annot_rec rec)\r
+{\r
+ int pt_type;\r
+ int p;\r
+ char opt_elms[200];\r
+ struct gpx_point pt;\r
+\r
+ if (! gpx_file)\r
+ {\r
+ return;\r
+ }\r
+\r
+ pt_type = GPX_TRKPT ;\r
+\r
+ // FIXME why do I need to assign memory for this?\r
+\r
+ if (use_gpx_route)\r
+ pt_type = GPX_RTEPT;\r
+ switch (rec.type)\r
+ {\r
+ case ANNOT_TYPE_LINE:\r
+\r
+ // FIXME lots of format and name info to be added here\r
+ if(use_gpx_route)\r
+ {\r
+ fprintf(gpx_file, "\t<rte>\n");\r
+ fprintf(gpx_file, "\t\t<src>Extracted from Annotation %d (%s)</src>\n",\r
+ rec.annot_num, annot_type_name[rec.type]);\r
+ fprintf(gpx_file, "\t\t<name>RT%04d</name>\n", rec.annot_num);\r
+ }\r
+ else\r
+ {\r
+ fprintf(gpx_file, "\t<trk>\n");\r
+ fprintf(gpx_file, "\t\t<name>TK%04d</name>\n", rec.annot_num);\r
+ fprintf(gpx_file, "\t\t<src>Extracted from Annotation %d (%s)</src>\n",\r
+ rec.annot_num, annot_type_name[rec.type]);\r
+ fprintf(gpx_file, "\t\t<trkseg>\n");\r
+ }\r
+\r
+ for (p=0; p < rec.line_points; p++)\r
+ {\r
+ pt=gpx_get_point(rec.buf+annot_head_len[rec.type]+12*p);\r
+ if(use_gpx_route)\r
+ sprintf(opt_elms, "<name>rp%04d</name>", p);\r
+ else\r
+ // we need to include a name for trackpoints\r
+ // for them to be recognised by easygps.\r
+ sprintf(opt_elms, "<name>tp%04d</name>", p);\r
+ gpx_write_point(pt, pt_type, opt_elms);\r
+ }\r
+ if(use_gpx_route)\r
+ fprintf(gpx_file, "\t</rte>\n");\r
+ else\r
+ fprintf(gpx_file, "\t\t</trkseg>\n\t</trk>\n");\r
+\r
+ case ANNOT_TYPE_OVAL:\r
+ case ANNOT_TYPE_TEXT:\r
+ case ANNOT_TYPE_CIRCLE:\r
+ default:\r
+ break;\r
+ }\r
+}\r
+\r
+int readbytes(FILE* file, char* buf, int bytes2read)\r
+{\r
+ // cant I just do this with fread?\r
+ int i;\r
+// int status;\r
+/* int readbyte;\r
+ for (i=0; i<bytes2read; i++)\r
+ {\r
+ readbyte = getc(file);\r
+ if(readbyte==EOF)\r
+ {\r
+ fprintf(stderr, "Unexpected end of file while reading %i bytes\n",bytes2read);\r
+ printf("Read %d of a required %d bytes\n", i+1, bytes2read);\r
+ printf("Dumping the buffer read before unexpected EOF\n");\r
+ printbuf(buf,i);\r
+ fflush(stdout);\r
+ return(1);\r
+ //exit(1);\r
+ }\r
+ buf[i] = readbyte;\r
+ if (verbose_flag > 5)\r
+ {\r
+ //printf("read byte from file %#x=%u=%c\n", readbyte,readbyte,readbyte);\r
+ //fflush(stdout);\r
+\r
+ }\r
+ }\r
+*/\r
+ i = fread(buf, 1, bytes2read, file);\r
+ if (i<bytes2read)\r
+ {\r
+ if (feof(file))\r
+ printf("Unexpected end of file\n");\r
+ else if (ferror(file))\r
+ perror("Unexpected error while reading from file");\r
+ printf("Read %d of a required %d bytes\n", i+1, bytes2read);\r
+ printf("Dumping the buffer read before unexpected EOF or error\n");\r
+ printbuf(buf,i);\r
+ fflush(stdout);\r
+ return(i);\r
+ }\r
+\r
+ if (verbose_flag > 5)\r
+ {\r
+ printf("Readbytes: Read %d bytes from file\n",bytes2read);\r
+ printbuf(buf, bytes2read);\r
+ fflush(stdout);\r
+ if (gpx_file)\r
+ fflush(gpx_file);\r
+\r
+ }\r
+ return(i);\r
+}\r
+\r
+struct annot_rec read_annot_rec(int annot_num)\r
+{\r
+ // new improved version!\r
+\r
+ int status;\r
+ int i;\r
+ struct annot_rec rec;\r
+ rec.buf = (char*)xmalloc(ANNOT_REC_HEAD_LEN);\r
+ // This read can fail because I have miscalculated number of records\r
+ // So exit gracefully\r
+ status = readbytes(annot_file, rec.buf, ANNOT_REC_HEAD_LEN);\r
+ if (status!=ANNOT_REC_HEAD_LEN)\r
+ {\r
+ gpx_write_file_trailer();\r
+ // exit(1)\r
+ // should do some cleaning up here\r
+ return rec;\r
+ }\r
+\r
+ rec.type = *(int*)(rec.buf+ANNOT_RECOS_TYPE);\r
+ rec.annot_num = *(int*)(rec.buf+ANNOT_RECOS_ANUM);\r
+ rec.text_length = *(int*)(rec.buf+ANNOT_RECOS_TEXTLEN);\r
+ rec.line_points=0;\r
+ if (rec.type == ANNOT_TYPE_LINE)\r
+ rec.line_points = *(int*)(rec.buf+ANNOT_RECOS_LINENUMPOINTS);\r
+ rec.length = annot_rec_len[rec.type] + 2*rec.text_length + 12*rec.line_points;\r
+\r
+ printf("Got annotation %d with internal id %d, of type %s, text length %d, and %d line points\n",\r
+ annot_num+1, rec.annot_num, annot_type_name[rec.type],\r
+ rec.text_length, rec.line_points);\r
+\r
+ rec.buf = (char*)xrealloc(rec.buf, rec.length);\r
+ status = readbytes(annot_file, rec.buf+ANNOT_REC_HEAD_LEN, rec.length - ANNOT_REC_HEAD_LEN);\r
+ if (status!=(rec.length - ANNOT_REC_HEAD_LEN))\r
+ {\r
+ gpx_write_file_trailer();\r
+ exit(1);\r
+ }\r
+\r
+ if(rec.text_length>0)\r
+ {\r
+ rec.text=(char*)xmalloc(rec.text_length+1);\r
+ rec.text[rec.text_length]=0x0;\r
+ for (i=0;i<rec.text_length;i++)\r
+ rec.text[i]=rec.buf[ANNOT_RECOS_TEXT+ 2*i];\r
+ //if (verbose_flag > 1)\r
+\r
+ printf("The sb text in the box is: %s\n", rec.text);\r
+ }\r
+\r
+ if (verbose_flag > 4)\r
+ {\r
+ printf("Recognised record with length %i\n",rec.length);\r
+ printbuf(rec.buf, rec.length);\r
+ }\r
+\r
+ return rec;\r
+}\r
+\r
+void process_annotations_stream(char* annot_file_name)\r
+{\r
+ // Read the annotation file header\r
+\r
+ int i;\r
+ int num_annotations;\r
+// int file_pos = ANNOT_FILE_HEAD_LEN;\r
+ annot_file_header file_header = (annot_file_header)xmalloc(ANNOT_FILE_HEAD_LEN);\r
+ int status;\r
+ struct annot_rec rec;\r
+ char* checkEOF;\r
+\r
+ if ((annot_file = fopen(annot_file_name, "rb")) == NULL)\r
+ {\r
+ fprintf(stderr, "Quitting because I cannot open %s\n", annot_file_name);\r
+ exit(1);\r
+ }\r
+\r
+ status=readbytes(annot_file, file_header, ANNOT_FILE_HEAD_LEN);\r
+ if (status!=ANNOT_FILE_HEAD_LEN)\r
+ {\r
+ printf("Cant make any more sense of annotations stream, continuing\n");\r
+ return;\r
+ }\r
+\r
+ // file_pos is for debugging only\r
+\r
+ for (i=1; i<8; i++)\r
+ if ( file_header[i] != std_annotfile_header[i] )\r
+ printf("Nonstandard annotations file header, header[%i]=0x%x, normal value is 0x%x\n",\r
+ i, file_header[i], std_annotfile_header[i] );\r
+\r
+ num_annotations = *(int*)(file_header+8);\r
+\r
+ if (verbose_flag > 1)\r
+ {\r
+ printf("Annotations file header indicates %i annotations in file\n",\r
+ num_annotations);\r
+ }\r
+\r
+ if (verbose_flag > 4)\r
+ {\r
+ printf("Dumping file header:\n");\r
+ printbuf(file_header, ANNOT_FILE_HEAD_LEN);\r
+ }\r
+\r
+ /*\r
+ ** Read all the annotation records\r
+ */\r
+ for (i=0; i < num_annotations; i++)\r
+ {\r
+ rec = read_annot_rec(i);\r
+\r
+ if (explore_flag)\r
+ explore_annot(rec);\r
+\r
+ gpx_write_annot_rec(rec);\r
+\r
+ free(rec.buf);\r
+ if (rec.text_length>0)\r
+ free(rec.text);\r
+ }\r
+\r
+ // Check that we are at the end of annotation file\r
+\r
+ checkEOF = xmalloc(4);\r
+ status=readbytes(annot_file, checkEOF, 4);\r
+ if ( (status!=4) || (checkEOF[0]!=0) || (checkEOF[1]!=0)\r
+ || (checkEOF[2]!=0) || (checkEOF[3]!=0) || (getc(annot_file)!=EOF) )\r
+ {\r
+ fprintf (stderr, "Did not finish reading annotation file at EOF\n");\r
+ if (gpx_file)\r
+ fprintf(gpx_file, GPX_FOOTER);\r
+ }\r
+ free(checkEOF);\r
+ fclose(annot_file);\r
+ fflush(stdout);\r
+ fflush(gpx_file);\r
+}\r
+\r
+struct jourwpt_rec * read_journey_rec(int jour_num)\r
+{\r
+ int i;\r
+ int status;\r
+ int readlen1 = JOURWPT_REC_HEAD_LEN;\r
+ int readlen2;\r
+ int readlen3;\r
+ char c;\r
+ struct jourwpt_rec * rec = (struct jourwpt_rec *)xmalloc(sizeof(struct jourwpt_rec));\r
+\r
+ rec->buf = (char*)xmalloc(readlen1);\r
+\r
+ status = readbytes(jour_file, rec->buf, readlen1);\r
+ if (status!=readlen1)\r
+ {\r
+ printf("Unexpected EOF while reading Journey route point %d part 1.\n", jour_num);\r
+ printf("Dumping Journey route point buffer read so far\n");\r
+ printbuf(rec->buf, status);\r
+ //FIXME free rec\r
+ return NULL;\r
+ }\r
+\r
+ // FIXME careful here\r
+ c = rec->buf[0];\r
+ rec->UdId = c;\r
+\r
+ c = rec->buf[JOURWPT_RECOS_STR1LEN];\r
+\r
+ rec->text1_length = (int)c;\r
+\r
+ if (verbose_flag > 5)\r
+ {\r
+ printf("Reading Journey routepoint, got buf part1, text1 len = %d\n",\r
+ rec->text1_length);\r
+ printbuf(rec->buf, readlen1);\r
+ }\r
+\r
+ readlen2 = rec->text1_length+4;\r
+\r
+ rec->buf = (char*)xrealloc(rec->buf, readlen1 + readlen2);\r
+ status = readbytes(jour_file, rec->buf+readlen1, readlen2);\r
+ if (status!=readlen2)\r
+ {\r
+ printf("Unexpected EOF while reading Journey route point %d part 2.\n", jour_num);\r
+ printf("Dumping Journey route point buffer read so far\n");\r
+ printbuf(rec->buf, readlen1+status);\r
+ //FIXME free rec\r
+ return NULL;\r
+ }\r
+\r
+ c = rec->buf[JOURWPT_RECOS_STR2LEN + rec->text1_length];\r
+ rec->text2_length = (int)c;\r
+ rec->buf_length = JOUR_WPTREC_LEN + rec->text1_length + 2*rec->text2_length;\r
+\r
+ if (verbose_flag > 5)\r
+ {\r
+ printf("got buf part2, text2 len = %d\n", rec->text2_length);\r
+ printbuf(rec->buf, readlen1 + readlen2);\r
+ }\r
+ readlen3 = rec->buf_length - readlen1 - readlen2;\r
+\r
+ rec->buf = (char*)xrealloc(rec->buf, rec->buf_length);\r
+ status = readbytes(jour_file, rec->buf+readlen1+readlen2, readlen3);\r
+ if (status!=readlen3)\r
+ {\r
+ printf("Unexpected EOF while reading Journey route point %d part 3.\n", jour_num);\r
+ printf("Dumping Journey route point buffer read so far\n");\r
+ printbuf(rec->buf, readlen1+readlen2+status);\r
+ //FIXME free rec\r
+ return NULL;\r
+ }\r
+\r
+ rec->text1=(char*)xmalloc(rec->text1_length+1);\r
+ rec->text2=(char*)xmalloc(rec->text2_length+1);\r
+ rec->text1[rec->text1_length]=0;\r
+ rec->text2[rec->text2_length]=0;\r
+ memcpy(rec->text1, rec->buf+JOURWPT_RECOS_STR1, rec->text1_length);\r
+ for (i=0; i<rec->text2_length; i++)\r
+ rec->text2[i]=rec->buf[JOURWPT_RECOS_STR2 + rec->text1_length+2*i];\r
+\r
+ if (verbose_flag > 3)\r
+ printf("got Journey routepoint UdId %d, text1 '%s', text2 '%s', length %d\n",\r
+ rec->UdId, rec->text1, rec->text2, rec->buf_length);\r
+\r
+ rec->pushpin = ppin_by_UdId(rec->UdId);\r
+\r
+ if (rec->pushpin != NULL)\r
+ {\r
+ if (verbose_flag > 5)\r
+ {\r
+ printf("Found probable pushpin match\n");\r
+ printf("pushpin name is: %s\n", rec->pushpin->UdName);\r
+ printf("Pushpin short note is: %s\n", rec->pushpin->NoteShort);\r
+ //printf("Pushpin long note is: %s\n", rec->pushpin->NoteLong);\r
+ }\r
+\r
+ gpx_write_jour_point(rec);\r
+ }\r
+ else\r
+ {\r
+ printf("*** Warning *** Ignoring route point '%s' without matching pushpin\n",\r
+ rec->text1);\r
+ printf("(yes, I should do someting more clever than this).\n");\r
+ if (rec->UdId)\r
+ printf("There should have been a matching pushin because UdId=%d\n", rec->UdId);\r
+ }\r
+ fflush(stdout);\r
+\r
+ if (verbose_flag > 4)\r
+ {\r
+ printf("Dumping the recognised Journey waypoint record\n");\r
+ printbuf(rec->buf, rec->buf_length);\r
+ }\r
+ return rec;\r
+}\r
+\r
+void process_journey_stream (char* jour_file_name)\r
+{\r
+ int journey_num_pts;\r
+ int j;\r
+ int readbyte;\r
+ static int verify_eof_flag = 0;\r
+ char* jour_file_header = (char*)xmalloc(JOUR_FILE_HEAD_LEN);\r
+ char* jour_file_trailer;\r
+ int max_read_more = 10000;\r
+ int readmore=0;\r
+ int status;\r
+ char readmorebuf[10000];\r
+ struct jourwpt_rec * rec;\r
+\r
+ gpx_write_jour_header();\r
+\r
+ printf("Processing Journey stream\n");\r
+ fflush(stdout);\r
+ fflush(gpx_file);\r
+\r
+\r
+ if ((jour_file = fopen(jour_file_name, "rb")) == NULL)\r
+ {\r
+ fprintf(stderr, "Quitting because I cannot open %s\n", jour_file_name);\r
+ exit(1);\r
+ }\r
+\r
+ status = readbytes(jour_file, jour_file_header, JOUR_FILE_HEAD_LEN);\r
+ if (status!=JOUR_FILE_HEAD_LEN)\r
+ {\r
+ printf("Unexpected EOF in the Journey stream\n");\r
+ gpx_write_jour_trailer();\r
+ return;\r
+ }\r
+\r
+ journey_num_pts = *(int*)(jour_file_header+JOUR_FILEOS_NUMREC);\r
+ printf("got Journey file header with %d waypoints\n", journey_num_pts);\r
+ if (verbose_flag > 4)\r
+ {\r
+ printbuf(jour_file_header, JOUR_FILE_HEAD_LEN);\r
+ }\r
+\r
+ for (j=0; j< journey_num_pts; j++)\r
+ {\r
+ rec = read_journey_rec(j);\r
+ if (rec==NULL)\r
+ {\r
+ printf("Closing stream and skipping rest of Journey stream processing because I read a bad record\n");\r
+ fclose(jour_file);\r
+ printf("Writing gpx route for Journey\n");\r
+ fflush(stdout);\r
+\r
+ gpx_write_jour_trailer();\r
+\r
+ printf("Finnished closing Journey stream after error.\n");\r
+ return;\r
+ }\r
+ }\r
+\r
+ jour_file_trailer = (char*)xmalloc(JOUR_FILE_TAIL_LEN);\r
+\r
+ status = readbytes(jour_file, jour_file_trailer, JOUR_FILE_TAIL_LEN);\r
+ if (status!=JOUR_FILE_TAIL_LEN)\r
+ {\r
+ printf("Unexpected EOF while reading journey stream trailer\n");\r
+ }\r
+\r
+ if (verbose_flag > 4)\r
+ {\r
+ printf("got Journey file trailer\n");\r
+ printbuf(jour_file_trailer, JOUR_FILE_TAIL_LEN);\r
+ }\r
+\r
+ if ((readbyte = getc(jour_file))!=EOF)\r
+ {\r
+ fprintf (stderr, "Did not finish reading journey file at EOF\n");\r
+\r
+ do {\r
+ readmorebuf[readmore]=(char)readbyte;\r
+ readmore++;\r
+ if (readmore>max_read_more)\r
+ break;\r
+ } while ((readbyte = getc(jour_file))!=EOF);\r
+\r
+ printf("read a further %d bytes past expected eof\n",readmore);\r
+ printbuf(readmorebuf, readmore);\r
+ }\r
+\r
+ fclose(jour_file);\r
+ printf("Writing gpx route for Journey\n");\r
+ fflush(stdout);\r
+\r
+ gpx_write_jour_trailer();\r
+\r
+ printf("Finnished proccessing Journey stream.\n");\r
+ fflush(stdout);\r
+ fflush(gpx_file);\r
+}\r
+\r
+void read_ppin_list_csv(char* ppin_file_name)\r
+// for reading my old style csv temp file for ppins\r
+{\r
+ int pinnum;\r
+ int params_read;\r
+ char ppin_line[500+MAX_PPIN_MEMO];\r
+ char ppin_line_strings[500+MAX_PPIN_MEMO];\r
+ struct pushpin * ppin;\r
+ char* status;\r
+ int UdNameLen=0;\r
+ int NoteShortLen=0;\r
+ int NoteLongLen=0;\r
+\r
+ printf("Annalysing the pushpin temp file\n");\r
+\r
+ for (pinnum=0; pinnum < MAX_PUSHPINS; pinnum++)\r
+ ppin_list[pinnum] = NULL;\r
+\r
+ if ((ppin_file = fopen(ppin_file_name, "r")) == NULL)\r
+ {\r
+ fprintf(stderr, "Cannot open %s\n", ppin_file_name);\r
+ exit(1);\r
+ }\r
+\r
+ pinnum=0;\r
+ while (!feof( ppin_file))\r
+ {\r
+ //printf("Reading pushpin %d\n", pinnum);\r
+ //fflush(stdout);\r
+\r
+ ppin = (struct pushpin *)xmalloc(sizeof(struct pushpin));\r
+\r
+ status=fgets(ppin_line, 500+MAX_PPIN_MEMO, ppin_file);\r
+\r
+ if (status==NULL)\r
+ {\r
+ printf("oops, trying to read empty line\n", pinnum);\r
+ break;\r
+\r
+ }\r
+ else\r
+ {\r
+ //printf("Read ppin temp line: %s\n", ppin_line);\r
+ //fflush(stdout);\r
+\r
+ params_read = sscanf(ppin_line, "%ld, %ld, %ld, %d, %d, %d, %[^\n]",\r
+ &(ppin->UdId), &(ppin->Grid), &(ppin->Precision),\r
+ &UdNameLen, &NoteShortLen, &NoteLongLen, ppin_line_strings);\r
+\r
+ printf("Got pushpin UdId %ld Grid %d Precision %d ppin_line_strings %s\n",\r
+ ppin->UdId, ppin->Grid, ppin->Precision, ppin_line_strings);\r
+ fflush(stdout);\r
+\r
+ if (params_read == 7)\r
+ {\r
+ ppin->UdName = (char*)xmalloc(UdNameLen+1);\r
+ memcpy(ppin->UdName, ppin_line_strings, UdNameLen);\r
+ ppin->UdName[UdNameLen]=0;\r
+\r
+ ppin->NoteShort = (char*)xmalloc(NoteShortLen+1);\r
+ memcpy(ppin->NoteShort, ppin_line_strings+UdNameLen, NoteShortLen);\r
+ ppin->NoteShort[NoteShortLen]=0;\r
+\r
+// ppin->NoteLong = (char*)xmalloc(NoteLongLen+1);\r
+// memcpy(ppin->NoteLong, ppin_line_strings+UdNameLen+NoteShortLen, NoteLongLen);\r
+// ppin->NoteLong[NoteLongLen]=0;\r
+\r
+ //printf("Read %d parameters ok\n", params_read);\r
+ //fflush(stdout);\r
+\r
+\r
+ ppin_list[pinnum]=ppin;\r
+ // printf("saving pushpin_linst[%d]: UdId %ld lat %g lon %g UdName %s\n",\r
+ // pinnum, ppin->UdId, ppin->lat, ppin->lon, ppin->UdName);\r
+ // fflush(stdout);\r
+ pinnum++;\r
+ }\r
+ else\r
+ {\r
+ printf("freeing this ppin (was# %d) because it did not read properly\n",\r
+ pinnum);\r
+ free(ppin);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ fclose(ppin_file);\r
+ printf("Read %d pushpins, now writing to gpx\n", pinnum);\r
+\r
+}\r
+\r
+int check_file_empty(char* filename)\r
+{\r
+ int readchar;\r
+ FILE* file=fopen(filename, "rb");\r
+ // also check if the file exists\r
+ if (file==NULL)\r
+ return 1;\r
+ readchar = fgetc(file);\r
+ if (readchar == EOF)\r
+ return 1;\r
+ else\r
+ return 0;\r
+}\r
+\r
+void process_pushpin_file(char* ppin_file_name)\r
+{\r
+ int i=0;\r
+ struct point p;\r
+ struct ms_point msp;\r
+\r
+ // dont try and open a empty mdb file\r
+ if (check_file_empty(ppin_file_name))\r
+ return;\r
+\r
+ read_ppin_list(ppin_file_name);\r
+ //read_ppin_list_csv(ppin_file_name);\r
+\r
+ // set lat & lon for all pushpins\r
+ while(ppin_list[i] && (i<MAX_PUSHPINS))\r
+ {\r
+ msp.grid = ppin_list[i]->Grid;\r
+ msp.precision = ppin_list[i]->Precision;\r
+ p = ms2latlong(msp);\r
+\r
+ ppin_list[i]->lat = p.lat;\r
+ ppin_list[i]->lon = p.lon;\r
+\r
+ if (verbose_flag > 3)\r
+ printf("Decoded pushpin %d lat %f, lon %f, UdName %s, NoteShort %s\n",\r
+ ppin_list[i]->UdId, ppin_list[i]->lat, ppin_list[i]->lon,\r
+ ppin_list[i]->UdName, ppin_list[i]->NoteShort);\r
+\r
+ i++;\r
+ }\r
+\r
+ gpx_write_pushpinlist();\r
+\r
+ printf("Finished reading pushpins\n");\r
+ fflush(stdout);\r
+ fflush(gpx_file);\r
+}\r
+\r
+void show_usage()\r
+{\r
+ printf("st2gpx - Export data from MS Streets & Trips and Autoroute to GPX format\n\n");\r
+ printf("Usage: st2gpx [-hre] [-v verbose-level] [-a annotations-file] [-u userdata-file] ");\r
+ printf("[-j journey-file] [-G gpx-file] stfile\n\n");\r
+ printf("-h : Help (this text)\n");\r
+ printf("-r : Export drawn-lines as routes instead of tracks\n");\r
+ printf("-e : Explore data furhter\n");\r
+ printf("-v [n] : Set debugging verbosity to 'n' (0-6, default 2)\n");\r
+ printf("-u userdata-file : Process pushpins in (mdb) file userdata-file\n");\r
+ printf("-j journey-file : Process Journey in file journey-file\n");\r
+ printf("-a annotations-file : Process Annotations in file annotations-file\n");\r
+ printf("-G gpx-file : Write output to gpx-file\n");\r
+ exit(0);\r
+}\r
+\r
+void xsystem(char* syscmd)\r
+// this is not ANSI\r
+{\r
+ int status;\r
+ printf("%s \n", syscmd);\r
+ _flushall();\r
+ status = system(syscmd);\r
+ if (status)\r
+ fprintf(stderr, "system call returned an error\n");\r
+}\r
+\r
+main(int argc, char** argv)\r
+{\r
+ int c;\r
+ static int verify_eof_flag = 0;\r
+ char* jour_file_name=NULL;\r
+ char* annot_file_name=NULL;\r
+ char* ppin_file_name=NULL;\r
+ char* gpx_file_name=NULL;\r
+\r
+ char syscmd[1000];\r
+ char cmddrv[_MAX_DRIVE];\r
+ char cmddir[_MAX_DIR];\r
+ char cmdfilename[_MAX_PATH];\r
+ char cmdext[_MAX_EXT];\r
+ char cmdpath[_MAX_PATH];\r
+\r
+ int debug_wait_flag=0;\r
+\r
+ while (1)\r
+ {\r
+ static struct option long_options[] =\r
+ {\r
+ {"file", required_argument, 0, 'f'},\r
+ {"outfile", required_argument, 0, 'F'},\r
+ {"verbose", optional_argument, 0, 'v'},\r
+ {"explore", no_argument, &explore_flag, 1},\r
+ {"route", no_argument, &use_gpx_route, 1},\r
+ {0, 0, 0, 0} // what is this for?\r
+ };\r
+ /* getopt_long stores the option index here. */\r
+ int option_index = 0;\r
+\r
+ // c = getopt_long (argc, argv, "v::bqderf:F:",\r
+ // long_options, &option_index);\r
+ c = getopt(argc, argv, "hu:j:a:G:rv::ew");\r
+\r
+ /* Detect the end of the options. */\r
+ if (c == -1)\r
+ break;\r
+\r
+ switch (c)\r
+ {\r
+ case 0:\r
+ /* If this option set a flag, do nothing else now. */\r
+ break;\r
+\r
+ case 'h':\r
+ show_usage();\r
+ break;\r
+\r
+ case 'u':\r
+ // read a UserData (pushpin) file directly\r
+ free(ppin_file_name);\r
+ ppin_file_name = (char*)xmalloc(strlen(optarg)+1);\r
+ strcpy(ppin_file_name, optarg);\r
+ if (verbose_flag > 1)\r
+ printf("Analysing UserData (pushpin) stream in file %s\n\n", jour_file_name);\r
+ break;\r
+\r
+ case 'j':\r
+ // read a Journey file directly\r
+ free(jour_file_name);\r
+ jour_file_name = (char*)xmalloc(strlen(optarg)+1);\r
+ strcpy(jour_file_name, optarg);\r
+ if (verbose_flag > 1)\r
+ printf("Analysing Journey stream in file %s\n\n", jour_file_name);\r
+ break;\r
+\r
+ case 'a':\r
+ // read an annotation file directly\r
+ annot_file_name = (char*)xmalloc(strlen(optarg)+1);\r
+ strcpy(annot_file_name, optarg);\r
+ if (verbose_flag > 1)\r
+ printf("Analysing Annotation stream in file %s\n\n", annot_file_name);\r
+ break;\r
+\r
+ case 'G':\r
+ gpx_file_name = (char*)xmalloc(200);\r
+ strcpy(gpx_file_name, optarg);\r
+ if (verbose_flag > 1)\r
+ printf("Writing GPX output to file %s\n\n", gpx_file_name);\r
+ break;\r
+\r
+ case 'r':\r
+ use_gpx_route=1;\r
+ break;\r
+\r
+ case 'v':\r
+ if (optarg==NULL)\r
+ verbose_flag=5;\r
+ else\r
+ verbose_flag = atoi(optarg);\r
+ break;\r
+\r
+ case 'e':\r
+ explore_flag = 1;\r
+ break;\r
+\r
+ case 'w':\r
+ debug_wait_flag = 1;\r
+ break;\r
+\r
+ case '?':\r
+ /* getopt_long already printed an error message. */\r
+ show_usage();\r
+ break;\r
+\r
+ default:\r
+ show_usage();\r
+ abort ();\r
+ }\r
+ }\r
+\r
+ if (optind == argc-1)\r
+ {\r
+ source_file_name = (char*)xmalloc(strlen(argv[optind])+1);\r
+ strcpy(source_file_name, argv[optind]);\r
+ if (verbose_flag > 1)\r
+ printf("Analysing autoroute file %s\n\n", source_file_name);\r
+ if (ppin_file_name==NULL)\r
+ {\r
+ ppin_file_name = (char*)xmalloc(strlen(source_file_name)+30);\r
+ sprintf(ppin_file_name, "%s.Contents\\UserData.mdb", source_file_name);\r
+ }\r
+ if (jour_file_name==NULL)\r
+ {\r
+ jour_file_name = (char*)xmalloc(strlen(source_file_name)+30);\r
+ sprintf(jour_file_name, "%s.Contents\\Journey", source_file_name);\r
+ }\r
+ if (annot_file_name==NULL)\r
+ {\r
+ annot_file_name = (char*)xmalloc(strlen(source_file_name)+30);\r
+ sprintf(annot_file_name, "%s.Contents\\Annotations", source_file_name);\r
+ }\r
+ if (gpx_file_name==NULL)\r
+ {\r
+ gpx_file_name = (char*)xmalloc(strlen(source_file_name)+30);\r
+ // should remove the est or axe suffix\r
+ sprintf(gpx_file_name, "%s.gpx", source_file_name);\r
+ }\r
+ }\r
+ else if (optind < argc-1)\r
+ {\r
+ printf("Unrecognised option %s\n", argv[optind+1]);\r
+ show_usage();\r
+ }\r
+ else\r
+ {\r
+ if (verbose_flag > 1)\r
+ printf("Not analysing any core S&T or autoroute file\n");\r
+ }\r
+\r
+ if (source_file_name)\r
+ {\r
+ // Open the compound file using the istorage utility\r
+ // I probably should do this in a library and use streams instead of files\r
+\r
+ // Find the path for istorage from the path in argv[0]\r
+\r
+ // this is not ANSI\r
+ _splitpath(argv[0], cmddrv, cmddir, cmdfilename, cmdext);\r
+ sprintf(cmdpath, "%s%s", cmddrv, cmddir);\r
+\r
+ sprintf(syscmd, "%sistorage\\istorage.exe %s", cmdpath, source_file_name);\r
+ xsystem(syscmd);\r
+\r
+ // clean up previous copy of this. It should already have been deleted...\r
+ sprintf(syscmd, "del %s.Contents\\UserData.mdb", source_file_name);\r
+ xsystem(syscmd);\r
+\r
+ sprintf(syscmd, "rename %s.Contents\\UserData. UserData.mdb", source_file_name);\r
+ xsystem(syscmd);\r
+ }\r
+\r
+ // begin processing the files\r
+ gpx_open_write_file_header(gpx_file_name);\r
+\r
+ if (ppin_file_name)\r
+ process_pushpin_file(ppin_file_name);\r
+ if (jour_file_name)\r
+ process_journey_stream(jour_file_name);\r
+ if (annot_file_name)\r
+ process_annotations_stream(annot_file_name);\r
+\r
+ gpx_write_file_trailer();\r
+\r
+\r
+ // Clean up the compound file directory\r
+ if (source_file_name)\r
+ {\r
+ sprintf(syscmd, "echo y|del %s.Contents", source_file_name);\r
+ xsystem(syscmd);\r
+\r
+ // just for debuging\r
+ if (debug_wait_flag)\r
+ {\r
+ fprintf(stderr, "kill that ado connection!\n");\r
+ fprintf(stderr, "Hit any key to continue\n");\r
+ getchar();\r
+ }\r
+\r
+ // how do I do this?\r
+ sprintf(syscmd, "del %s.Contents\\UserData.mdb", source_file_name);\r
+ xsystem(syscmd);\r
+\r
+ sprintf(syscmd, "rmdir %s.Contents", source_file_name);\r
+ xsystem(syscmd);\r
+ }\r
+\r
+ // just for debuging\r
+ if (debug_wait_flag)\r
+ {\r
+ fprintf(stderr, "Hit any key to continue\n");\r
+ getchar();\r
+ }\r
+}\r
--- /dev/null
+# Microsoft Developer Studio Project File - Name="st2gpx" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=st2gpx - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "st2gpx.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "st2gpx.mak" CFG="st2gpx - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "st2gpx - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "st2gpx - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF "$(CFG)" == "st2gpx - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF "$(CFG)" == "st2gpx - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /W4 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "st2gpx - Win32 Release"\r
+# Name "st2gpx - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\getopt.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\pushpins.cpp\r
+\r
+!IF "$(CFG)" == "st2gpx - Win32 Release"\r
+\r
+!ELSEIF "$(CFG)" == "st2gpx - Win32 Debug"\r
+\r
+# ADD CPP /W4\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\st2gpx.c\r
+\r
+!IF "$(CFG)" == "st2gpx - Win32 Release"\r
+\r
+!ELSEIF "$(CFG)" == "st2gpx - Win32 Debug"\r
+\r
+# ADD CPP /Za\r
+\r
+!ENDIF \r
+\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\getopt.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\pushpins.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
--- /dev/null
+Microsoft Developer Studio Workspace File, Format Version 6.00\r
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
+\r
+###############################################################################\r
+\r
+Project: "VCADO"="..\..\..\sw\5191\Rosetta\CPP\#Import-upg\Vcado.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "st2gpx"=.\st2gpx.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Global:\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<3>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r